mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-07 07:50:27 +00:00
Move all event handlers to a common class
While this does now involve a little more indirection, by having a single location for all hooks it's much easier to keep event listeners consistent between loaders. The diff is pretty noisy (I've inlined some classes, and ClientRegistry got a big restructure), but functionality should be the same.
This commit is contained in:
parent
e8f9cdd221
commit
0908acbe9b
@ -24,6 +24,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.config.ModConfigEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.registries.NewRegistryEvent;
|
||||
import net.minecraftforge.registries.RegistryBuilder;
|
||||
@ -113,4 +114,13 @@ public final class ComputerCraft {
|
||||
ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void sync(ModConfigEvent.Loading event) {
|
||||
Config.sync(event.getConfig());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void sync(ModConfigEvent.Reloading event) {
|
||||
Config.sync(event.getConfig());
|
||||
}
|
||||
}
|
||||
|
@ -5,33 +5,158 @@
|
||||
*/
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
import dan200.computercraft.client.render.CableHighlightRenderer;
|
||||
import dan200.computercraft.client.render.ItemPocketRenderer;
|
||||
import dan200.computercraft.client.render.ItemPrintoutRenderer;
|
||||
import dan200.computercraft.client.render.MonitorHighlightRenderer;
|
||||
import dan200.computercraft.client.sound.SpeakerManager;
|
||||
import dan200.computercraft.shared.CommonHooks;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.media.items.ItemPrintout;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
|
||||
import net.minecraftforge.event.level.LevelEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public class ClientHooks {
|
||||
@SubscribeEvent
|
||||
public static void onWorldUnload(LevelEvent.Unload event) {
|
||||
if (event.getLevel().isClientSide()) {
|
||||
ClientMonitor.destroyAll();
|
||||
SpeakerManager.reset();
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Event listeners for client-only code.
|
||||
* <p>
|
||||
* This is the client-only version of {@link CommonHooks}, and so should be where all client-specific event handlers are
|
||||
* defined.
|
||||
*/
|
||||
public final class ClientHooks {
|
||||
private ClientHooks() {
|
||||
}
|
||||
|
||||
public static void onTick() {
|
||||
FrameInfo.onTick();
|
||||
}
|
||||
|
||||
public static void onRenderTick() {
|
||||
PauseAwareTimer.tick(Minecraft.getInstance().isPaused());
|
||||
FrameInfo.onRenderTick();
|
||||
}
|
||||
|
||||
public static void onWorldUnload() {
|
||||
ClientMonitor.destroyAll();
|
||||
SpeakerManager.reset();
|
||||
ClientPocketComputers.reset();
|
||||
}
|
||||
|
||||
public static boolean onChatMessage(String message) {
|
||||
return handleOpenComputerCommand(message);
|
||||
}
|
||||
|
||||
public static boolean drawHighlight(PoseStack transform, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) {
|
||||
return CableHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit)
|
||||
|| MonitorHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit);
|
||||
}
|
||||
|
||||
public static boolean onRenderHeldItem(
|
||||
PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand,
|
||||
float pitch, float equipProgress, float swingProgress, ItemStack stack
|
||||
) {
|
||||
if (stack.getItem() instanceof ItemPocketComputer) {
|
||||
ItemPocketRenderer.INSTANCE.renderItemFirstPerson(transform, render, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||
return true;
|
||||
}
|
||||
if (stack.getItem() instanceof ItemPrintout) {
|
||||
ItemPrintoutRenderer.INSTANCE.renderItemFirstPerson(transform, render, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean onRenderItemFrame(PoseStack transform, MultiBufferSource render, ItemFrame frame, ItemStack stack, int light) {
|
||||
if (stack.getItem() instanceof ItemPrintout) {
|
||||
ItemPrintoutRenderer.onRenderInFrame(transform, render, frame, stack, light);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void onPlayStreaming(SoundEngine engine, Channel channel, AudioStream stream) {
|
||||
SpeakerManager.onPlayStreaming(engine, channel, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the {@link CommandComputerCraft#OPEN_COMPUTER} "clientside command". This isn't a true command, as we
|
||||
* don't want it to actually be visible to the user.
|
||||
*
|
||||
* @param message The current chat message.
|
||||
* @return Whether to cancel sending this message.
|
||||
*/
|
||||
private static boolean handleOpenComputerCommand(String message) {
|
||||
if (!message.startsWith(CommandComputerCraft.OPEN_COMPUTER)) return false;
|
||||
|
||||
var server = Minecraft.getInstance().getSingleplayerServer();
|
||||
if (server == null) return false;
|
||||
|
||||
var idStr = message.substring(CommandComputerCraft.OPEN_COMPUTER.length()).trim();
|
||||
int id;
|
||||
try {
|
||||
id = Integer.parseInt(idStr);
|
||||
} catch (NumberFormatException ignore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var file = new File(ServerContext.get(server).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) return false;
|
||||
|
||||
Util.getPlatform().openFile(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional information about the currently targeted block to the debug screen.
|
||||
*
|
||||
* @param addText A callback which adds a single line of text.
|
||||
*/
|
||||
public static void addDebugInfo(Consumer<String> addText) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
if (!minecraft.options.renderDebug || minecraft.level == null) return;
|
||||
if (minecraft.hitResult == null || minecraft.hitResult.getType() != HitResult.Type.BLOCK) return;
|
||||
|
||||
var tile = minecraft.level.getBlockEntity(((BlockHitResult) minecraft.hitResult).getBlockPos());
|
||||
|
||||
if (tile instanceof TileMonitor monitor) {
|
||||
addText.accept("");
|
||||
addText.accept(
|
||||
String.format("Targeted monitor: (%d, %d), %d x %d", monitor.getXIndex(), monitor.getYIndex(), monitor.getWidth(), monitor.getHeight())
|
||||
);
|
||||
} else if (tile instanceof TileTurtle turtle) {
|
||||
addText.accept("");
|
||||
addText.accept("Targeted turtle:");
|
||||
addText.accept(String.format("Id: %d", turtle.getComputerID()));
|
||||
addTurtleUpgrade(addText, turtle, TurtleSide.LEFT);
|
||||
addTurtleUpgrade(addText, turtle, TurtleSide.RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLogIn(ClientPlayerNetworkEvent.LoggingIn event) {
|
||||
ClientPocketComputers.reset();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLogOut(ClientPlayerNetworkEvent.LoggingOut event) {
|
||||
ClientPocketComputers.reset();
|
||||
private static void addTurtleUpgrade(Consumer<String> out, TileTurtle turtle, TurtleSide side) {
|
||||
var upgrade = turtle.getUpgrade(side);
|
||||
if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.getUpgradeID()));
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ import dan200.computercraft.api.client.ComputerCraftAPIClient;
|
||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||
import dan200.computercraft.client.gui.*;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
||||
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
|
||||
import dan200.computercraft.client.render.TurtleModelLoader;
|
||||
import dan200.computercraft.client.turtle.TurtleModemModeller;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
@ -21,26 +21,86 @@ import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
|
||||
import dan200.computercraft.shared.media.items.ItemDisk;
|
||||
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
import net.minecraft.client.renderer.ShaderInstance;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.client.renderer.item.ItemPropertyFunction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ModelEvent;
|
||||
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Registers textures and models for items.
|
||||
* Registers client-side objects, such as {@link BlockEntityRendererProvider}s and
|
||||
* {@link MenuScreens.ScreenConstructor}.
|
||||
* <p>
|
||||
* The functions in this class should be called from a loader-specific class.
|
||||
*
|
||||
* @see ModRegistry The common registry for actual game objects.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public final class ClientRegistry {
|
||||
private ClientRegistry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any client-side objects which don't have to be done on the main thread.
|
||||
*/
|
||||
public static void register() {
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_speaker_left"),
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_speaker_right")
|
||||
));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_crafting_table_left"),
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_crafting_table_right")
|
||||
));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any client-side objects which must be done on the main thread.
|
||||
*/
|
||||
public static void registerMainThread() {
|
||||
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register(ModRegistry.Menus.COMPUTER.get(), GuiComputer::new);
|
||||
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register(ModRegistry.Menus.POCKET_COMPUTER.get(), GuiComputer::new);
|
||||
MenuScreens.<ContainerComputerBase, NoTermComputerScreen<ContainerComputerBase>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
|
||||
MenuScreens.register(ModRegistry.Menus.TURTLE.get(), GuiTurtle::new);
|
||||
|
||||
MenuScreens.register(ModRegistry.Menus.PRINTER.get(), GuiPrinter::new);
|
||||
MenuScreens.register(ModRegistry.Menus.DISK_DRIVE.get(), GuiDiskDrive::new);
|
||||
MenuScreens.register(ModRegistry.Menus.PRINTOUT.get(), GuiPrintout::new);
|
||||
|
||||
MenuScreens.<ContainerViewComputer, GuiComputer<ContainerViewComputer>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), GuiComputer::new);
|
||||
|
||||
registerItemProperty("state",
|
||||
(stack, world, player, random) -> ClientPocketComputers.get(stack).getState().ordinal(),
|
||||
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
||||
);
|
||||
registerItemProperty("coloured",
|
||||
(stack, world, player, random) -> IColouredItem.getColourBasic(stack) != -1 ? 1 : 0,
|
||||
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
||||
);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("deprecation")
|
||||
private static void registerItemProperty(String name, ItemPropertyFunction getter, Supplier<? extends Item>... items) {
|
||||
var id = new ResourceLocation(ComputerCraft.MOD_ID, name);
|
||||
for (var item : items) ItemProperties.register(item.get(), id, getter);
|
||||
}
|
||||
|
||||
private static final String[] EXTRA_MODELS = new String[]{
|
||||
// Turtle upgrades
|
||||
"block/turtle_modem_normal_off_left",
|
||||
@ -64,114 +124,63 @@ public final class ClientRegistry {
|
||||
"block/turtle_elf_overlay",
|
||||
};
|
||||
|
||||
private ClientRegistry() {
|
||||
public static void registerExtraModels(Consumer<ResourceLocation> register) {
|
||||
for (var model : EXTRA_MODELS) register.accept(new ResourceLocation(ComputerCraft.MOD_ID, model));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerModelLoaders(ModelEvent.RegisterGeometryLoaders event) {
|
||||
event.register("turtle", TurtleModelLoader.INSTANCE);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerModels(ModelEvent.RegisterAdditional event) {
|
||||
for (var model : EXTRA_MODELS) {
|
||||
event.register(new ResourceLocation(ComputerCraft.MOD_ID, model));
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onItemColours(RegisterColorHandlersEvent.Item event) {
|
||||
public static void registerItemColours(BiConsumer<ItemColor, ItemLike> register) {
|
||||
if (ModRegistry.Items.DISK == null || ModRegistry.Blocks.TURTLE_NORMAL == null) {
|
||||
ComputerCraft.log.warn("Block/item registration has failed. Skipping registration of item colours.");
|
||||
return;
|
||||
}
|
||||
|
||||
event.register(
|
||||
register.accept(
|
||||
(stack, layer) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour(stack) : 0xFFFFFF,
|
||||
ModRegistry.Items.DISK.get()
|
||||
);
|
||||
|
||||
event.register(
|
||||
register.accept(
|
||||
(stack, layer) -> layer == 1 ? ItemTreasureDisk.getColour(stack) : 0xFFFFFF,
|
||||
ModRegistry.Items.TREASURE_DISK.get()
|
||||
);
|
||||
|
||||
event.register((stack, layer) -> {
|
||||
switch (layer) {
|
||||
case 0:
|
||||
default:
|
||||
return 0xFFFFFF;
|
||||
case 1: // Frame colour
|
||||
return IColouredItem.getColourBasic(stack);
|
||||
case 2: { // Light colour
|
||||
var light = ClientPocketComputers.get(stack).getLightState();
|
||||
return light == -1 ? Colour.BLACK.getHex() : light;
|
||||
}
|
||||
register.accept(ClientRegistry::getPocketColour, ModRegistry.Items.POCKET_COMPUTER_NORMAL.get());
|
||||
register.accept(ClientRegistry::getPocketColour, ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
|
||||
|
||||
register.accept(ClientRegistry::getTurtleColour, ModRegistry.Blocks.TURTLE_NORMAL.get());
|
||||
register.accept(ClientRegistry::getTurtleColour, ModRegistry.Blocks.TURTLE_ADVANCED.get());
|
||||
}
|
||||
|
||||
private static int getPocketColour(ItemStack stack, int layer) {
|
||||
switch (layer) {
|
||||
case 0:
|
||||
default:
|
||||
return 0xFFFFFF;
|
||||
case 1: // Frame colour
|
||||
return IColouredItem.getColourBasic(stack);
|
||||
case 2: { // Light colour
|
||||
var light = ClientPocketComputers.get(stack).getLightState();
|
||||
return light == -1 ? Colour.BLACK.getHex() : light;
|
||||
}
|
||||
}, ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
|
||||
|
||||
// Setup turtle colours
|
||||
event.register(
|
||||
(stack, tintIndex) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour(stack) : 0xFFFFFF,
|
||||
ModRegistry.Blocks.TURTLE_NORMAL.get(), ModRegistry.Blocks.TURTLE_ADVANCED.get()
|
||||
);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void setupClient(FMLClientSetupEvent event) {
|
||||
// Setup TESRs
|
||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_NORMAL.get(), TileEntityMonitorRenderer::new);
|
||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), TileEntityMonitorRenderer::new);
|
||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), TileEntityTurtleRenderer::new);
|
||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new);
|
||||
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_speaker_left"),
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_speaker_right")
|
||||
));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_crafting_table_left"),
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "block/turtle_crafting_table_right")
|
||||
));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
||||
|
||||
event.enqueueWork(() -> {
|
||||
registerContainers();
|
||||
|
||||
registerItemProperty("state",
|
||||
(stack, world, player, random) -> ClientPocketComputers.get(stack).getState().ordinal(),
|
||||
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
||||
);
|
||||
registerItemProperty("coloured",
|
||||
(stack, world, player, random) -> IColouredItem.getColourBasic(stack) != -1 ? 1 : 0,
|
||||
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static void registerItemProperty(String name, ItemPropertyFunction getter, Supplier<? extends Item>... items) {
|
||||
var id = new ResourceLocation(ComputerCraft.MOD_ID, name);
|
||||
for (var item : items) {
|
||||
ItemProperties.register(item.get(), id, getter);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getTurtleColour(ItemStack stack, int layer) {
|
||||
return layer == 0 ? ((IColouredItem) stack.getItem()).getColour(stack) : 0xFFFFFF;
|
||||
}
|
||||
|
||||
private static void registerContainers() {
|
||||
// My IDE doesn't think so, but we do actually need these generics.
|
||||
public static void registerBlockEntityRenderers(BlockEntityRenderRegistry register) {
|
||||
register.register(ModRegistry.BlockEntities.MONITOR_NORMAL.get(), TileEntityMonitorRenderer::new);
|
||||
register.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), TileEntityMonitorRenderer::new);
|
||||
register.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), TileEntityTurtleRenderer::new);
|
||||
register.register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new);
|
||||
}
|
||||
|
||||
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register(ModRegistry.Menus.COMPUTER.get(), GuiComputer::new);
|
||||
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register(ModRegistry.Menus.POCKET_COMPUTER.get(), GuiComputer::new);
|
||||
MenuScreens.<ContainerComputerBase, NoTermComputerScreen<ContainerComputerBase>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
|
||||
MenuScreens.register(ModRegistry.Menus.TURTLE.get(), GuiTurtle::new);
|
||||
public interface BlockEntityRenderRegistry {
|
||||
<T extends BlockEntity> void register(BlockEntityType<? extends T> type, BlockEntityRendererProvider<T> provider);
|
||||
}
|
||||
|
||||
MenuScreens.register(ModRegistry.Menus.PRINTER.get(), GuiPrinter::new);
|
||||
MenuScreens.register(ModRegistry.Menus.DISK_DRIVE.get(), GuiDiskDrive::new);
|
||||
MenuScreens.register(ModRegistry.Menus.PRINTOUT.get(), GuiPrintout::new);
|
||||
|
||||
MenuScreens.<ContainerViewComputer, GuiComputer<ContainerViewComputer>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), GuiComputer::new);
|
||||
public static void registerShaders(ResourceManager resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
|
||||
RenderTypes.registerShaders(resources, load);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.sound.SpeakerSound;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.*;
|
||||
import net.minecraftforge.client.event.sound.PlayStreamingSourceEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.level.LevelEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
/**
|
||||
* Forge-specific dispatch for {@link ClientHooks}.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public final class ForgeClientHooks {
|
||||
private ForgeClientHooks() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) ClientHooks.onTick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderTick(TickEvent.RenderTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) ClientHooks.onRenderTick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onWorldUnload(LevelEvent.Unload event) {
|
||||
if (event.getLevel().isClientSide()) ClientHooks.onWorldUnload();
|
||||
}
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public static void drawHighlight(RenderHighlightEvent.Block event) {
|
||||
if (ClientHooks.drawHighlight(event.getPoseStack(), event.getMultiBufferSource(), event.getCamera(), event.getTarget())) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClientSendMessage(ClientChatEvent event) {
|
||||
if (ClientHooks.onChatMessage(event.getMessage())) event.setCanceled(true);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderText(CustomizeGuiOverlayEvent.DebugText event) {
|
||||
ClientHooks.addDebugInfo(event.getRight()::add);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderInHand(RenderHandEvent event) {
|
||||
if (ClientHooks.onRenderHeldItem(
|
||||
event.getPoseStack(), event.getMultiBufferSource(), event.getPackedLight(),
|
||||
event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack()
|
||||
)) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderInFrame(RenderItemInFrameEvent event) {
|
||||
if (ClientHooks.onRenderItemFrame(
|
||||
event.getPoseStack(), event.getMultiBufferSource(), event.getItemFrameEntity(), event.getItemStack(), event.getPackedLight()
|
||||
)) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void playStreaming(PlayStreamingSourceEvent event) {
|
||||
if (!(event.getSound() instanceof SpeakerSound sound) || sound.getStream() == null) return;
|
||||
ClientHooks.onPlayStreaming(event.getEngine(), event.getChannel(), sound.getStream());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.render.TurtleModelLoader;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ModelEvent;
|
||||
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
|
||||
import net.minecraftforge.client.event.RegisterShadersEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Registers textures and models for items.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public final class ForgeClientRegistry {
|
||||
private ForgeClientRegistry() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerModelLoaders(ModelEvent.RegisterGeometryLoaders event) {
|
||||
event.register("turtle", TurtleModelLoader.INSTANCE);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerModels(ModelEvent.RegisterAdditional event) {
|
||||
ClientRegistry.registerExtraModels(event::register);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerShaders(RegisterShadersEvent event) throws IOException {
|
||||
ClientRegistry.registerShaders(event.getResourceManager(), event::registerShader);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onItemColours(RegisterColorHandlersEvent.Item event) {
|
||||
ClientRegistry.registerItemColours(event::register);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void setupClient(FMLClientSetupEvent event) {
|
||||
ClientRegistry.register();
|
||||
ClientRegistry.registerBlockEntityRenderers(BlockEntityRenderers::register);
|
||||
|
||||
event.enqueueWork(ClientRegistry::registerMainThread);
|
||||
}
|
||||
}
|
@ -5,13 +5,6 @@
|
||||
*/
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public final class FrameInfo {
|
||||
private static int tick;
|
||||
private static long renderFrame;
|
||||
@ -27,13 +20,11 @@ public final class FrameInfo {
|
||||
return renderFrame;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) tick++;
|
||||
public static void onTick() {
|
||||
tick++;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderTick(TickEvent.RenderTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) renderFrame++;
|
||||
public static void onRenderTick() {
|
||||
renderFrame++;
|
||||
}
|
||||
}
|
||||
|
@ -5,19 +5,17 @@
|
||||
*/
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderHighlightEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public final class CableHighlightRenderer {
|
||||
private CableHighlightRenderer() {
|
||||
}
|
||||
@ -25,37 +23,36 @@ public final class CableHighlightRenderer {
|
||||
/**
|
||||
* Draw an outline for a specific part of a cable "Multipart".
|
||||
*
|
||||
* @param event The event to observe
|
||||
* @param transform The current transformation matrix.
|
||||
* @param bufferSource The buffer to draw to.
|
||||
* @param camera The current camera.
|
||||
* @param hit The block hit result for the current player.
|
||||
* @return If we rendered a custom outline.
|
||||
* @see net.minecraft.client.renderer.LevelRenderer#renderHitOutline
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void drawHighlight(RenderHighlightEvent.Block event) {
|
||||
var hit = event.getTarget();
|
||||
public static boolean drawHighlight(PoseStack transform, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) {
|
||||
var pos = hit.getBlockPos();
|
||||
var world = event.getCamera().getEntity().getCommandSenderWorld();
|
||||
var info = event.getCamera();
|
||||
var world = camera.getEntity().getCommandSenderWorld();
|
||||
|
||||
var state = world.getBlockState(pos);
|
||||
|
||||
// We only care about instances with both cable and modem.
|
||||
if (state.getBlock() != ModRegistry.Blocks.CABLE.get() || state.getValue(BlockCable.MODEM).getFacing() == null || !state.getValue(BlockCable.CABLE)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
event.setCanceled(true);
|
||||
|
||||
var shape = WorldUtil.isVecInside(CableShapes.getModemShape(state), hit.getLocation().subtract(pos.getX(), pos.getY(), pos.getZ()))
|
||||
? CableShapes.getModemShape(state)
|
||||
: CableShapes.getCableShape(state);
|
||||
|
||||
var cameraPos = info.getPosition();
|
||||
var cameraPos = camera.getPosition();
|
||||
var xOffset = pos.getX() - cameraPos.x();
|
||||
var yOffset = pos.getY() - cameraPos.y();
|
||||
var zOffset = pos.getZ() - cameraPos.z();
|
||||
|
||||
var buffer = event.getMultiBufferSource().getBuffer(RenderType.lines());
|
||||
var matrix4f = event.getPoseStack().last().pose();
|
||||
var normal = event.getPoseStack().last().normal();
|
||||
var buffer = bufferSource.getBuffer(RenderType.lines());
|
||||
var matrix4f = transform.last().pose();
|
||||
var normal = transform.last().normal();
|
||||
// TODO: Can we just accesstransformer out LevelRenderer.renderShape?
|
||||
shape.forAllEdges((x1, y1, z1, x2, y2, z2) -> {
|
||||
var xDelta = (float) (x2 - x1);
|
||||
@ -77,5 +74,7 @@ public final class CableHighlightRenderer {
|
||||
.normal(normal, xDelta, yDelta, zDelta)
|
||||
.endVertex();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public class DebugOverlay {
|
||||
@SubscribeEvent
|
||||
public static void onRenderText(CustomizeGuiOverlayEvent.DebugText event) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
if (!minecraft.options.renderDebug || minecraft.level == null) return;
|
||||
if (minecraft.hitResult == null || minecraft.hitResult.getType() != HitResult.Type.BLOCK) return;
|
||||
|
||||
var tile = minecraft.level.getBlockEntity(((BlockHitResult) minecraft.hitResult).getBlockPos());
|
||||
|
||||
if (tile instanceof TileMonitor monitor) {
|
||||
event.getRight().add("");
|
||||
event.getRight().add(
|
||||
String.format("Targeted monitor: (%d, %d), %d x %d", monitor.getXIndex(), monitor.getYIndex(), monitor.getWidth(), monitor.getHeight())
|
||||
);
|
||||
} else if (tile instanceof TileTurtle turtle) {
|
||||
event.getRight().add("");
|
||||
event.getRight().add("Targeted turtle:");
|
||||
event.getRight().add(String.format("Id: %d", turtle.getComputerID()));
|
||||
addTurtleUpgrade(event.getRight(), turtle, TurtleSide.LEFT);
|
||||
addTurtleUpgrade(event.getRight(), turtle, TurtleSide.RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTurtleUpgrade(List<String> out, TileTurtle turtle, TurtleSide side) {
|
||||
var upgrade = turtle.getUpgrade(side);
|
||||
if (upgrade != null) out.add(String.format("Upgrade[%s]: %s", side, upgrade.getUpgradeID()));
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ public abstract class ItemMapLikeRenderer {
|
||||
*/
|
||||
protected abstract void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light);
|
||||
|
||||
protected void renderItemFirstPerson(PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
public void renderItemFirstPerson(PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
Player player = Minecraft.getInstance().player;
|
||||
|
||||
transform.pushPose();
|
||||
|
@ -8,7 +8,6 @@ package dan200.computercraft.client.render;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
import com.mojang.math.Vector3f;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
@ -16,10 +15,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
@ -28,25 +23,12 @@ import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FON
|
||||
/**
|
||||
* Emulates map rendering for pocket computers.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public final class ItemPocketRenderer extends ItemMapLikeRenderer {
|
||||
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
|
||||
public static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
|
||||
|
||||
private ItemPocketRenderer() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderInHand(RenderHandEvent event) {
|
||||
var stack = event.getItemStack();
|
||||
if (!(stack.getItem() instanceof ItemPocketComputer)) return;
|
||||
|
||||
event.setCanceled(true);
|
||||
INSTANCE.renderItemFirstPerson(
|
||||
event.getPoseStack(), event.getMultiBufferSource(), event.getPackedLight(),
|
||||
event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderItem(PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light) {
|
||||
var computer = ClientPocketComputers.get(stack);
|
||||
|
@ -7,16 +7,11 @@ package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Vector3f;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.media.items.ItemPrintout;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.client.event.RenderItemInFrameEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
@ -27,25 +22,12 @@ import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENG
|
||||
/**
|
||||
* Emulates map and item-frame rendering for printouts.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public final class ItemPrintoutRenderer extends ItemMapLikeRenderer {
|
||||
private static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer();
|
||||
public static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer();
|
||||
|
||||
private ItemPrintoutRenderer() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderInHand(RenderHandEvent event) {
|
||||
var stack = event.getItemStack();
|
||||
if (!(stack.getItem() instanceof ItemPrintout)) return;
|
||||
|
||||
event.setCanceled(true);
|
||||
INSTANCE.renderItemFirstPerson(
|
||||
event.getPoseStack(), event.getMultiBufferSource(), event.getPackedLight(),
|
||||
event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) {
|
||||
transform.mulPose(Vector3f.XP.rotationDegrees(180f));
|
||||
@ -55,13 +37,8 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer {
|
||||
drawPrintout(transform, render, stack, light);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderInFrame(RenderItemInFrameEvent event) {
|
||||
var stack = event.getItemStack();
|
||||
public static void onRenderInFrame(PoseStack transform, MultiBufferSource render, ItemFrame frame, ItemStack stack, int packedLight) {
|
||||
if (!(stack.getItem() instanceof ItemPrintout)) return;
|
||||
event.setCanceled(true);
|
||||
|
||||
var transform = event.getPoseStack();
|
||||
|
||||
// Move a little bit forward to ensure we're not clipping with the frame
|
||||
transform.translate(0.0f, 0.0f, -0.001f);
|
||||
@ -69,8 +46,8 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer {
|
||||
transform.scale(0.95f, 0.95f, -0.95f);
|
||||
transform.translate(-0.5f, -0.5f, 0.0f);
|
||||
|
||||
var light = event.getItemFrameEntity().getType() == EntityType.GLOW_ITEM_FRAME ? 0xf000d2 : event.getPackedLight(); // See getLightVal.
|
||||
drawPrintout(transform, event.getMultiBufferSource(), stack, light);
|
||||
var light = frame.getType() == EntityType.GLOW_ITEM_FRAME ? 0xf000d2 : packedLight; // See getLightVal.
|
||||
drawPrintout(transform, render, stack, light);
|
||||
}
|
||||
|
||||
private static void drawPrintout(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) {
|
||||
|
@ -5,17 +5,16 @@
|
||||
*/
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Matrix3f;
|
||||
import com.mojang.math.Matrix4f;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderHighlightEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
@ -25,23 +24,19 @@ import static net.minecraft.core.Direction.*;
|
||||
* Overrides monitor highlighting to only render the outline of the <em>whole</em> monitor, rather than the current
|
||||
* block. This means you do not get an intrusive outline on top of the screen.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public final class MonitorHighlightRenderer {
|
||||
private MonitorHighlightRenderer() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void drawHighlight(RenderHighlightEvent.Block event) {
|
||||
public static boolean drawHighlight(PoseStack transformStack, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) {
|
||||
// Preserve normal behaviour when crouching.
|
||||
if (event.getCamera().getEntity().isCrouching()) return;
|
||||
if (camera.getEntity().isCrouching()) return false;
|
||||
|
||||
var world = event.getCamera().getEntity().getCommandSenderWorld();
|
||||
var pos = event.getTarget().getBlockPos();
|
||||
var world = camera.getEntity().getCommandSenderWorld();
|
||||
var pos = hit.getBlockPos();
|
||||
|
||||
var tile = world.getBlockEntity(pos);
|
||||
if (!(tile instanceof TileMonitor monitor)) return;
|
||||
|
||||
event.setCanceled(true);
|
||||
if (!(tile instanceof TileMonitor monitor)) return false;
|
||||
|
||||
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
|
||||
var faces = EnumSet.allOf(Direction.class);
|
||||
@ -52,13 +47,12 @@ public final class MonitorHighlightRenderer {
|
||||
if (monitor.getYIndex() != 0) faces.remove(monitor.getDown().getOpposite());
|
||||
if (monitor.getYIndex() != monitor.getHeight() - 1) faces.remove(monitor.getDown());
|
||||
|
||||
var transformStack = event.getPoseStack();
|
||||
var cameraPos = event.getCamera().getPosition();
|
||||
var cameraPos = camera.getPosition();
|
||||
transformStack.pushPose();
|
||||
transformStack.translate(pos.getX() - cameraPos.x(), pos.getY() - cameraPos.y(), pos.getZ() - cameraPos.z());
|
||||
|
||||
// I wish I could think of a better way to do this
|
||||
var buffer = event.getMultiBufferSource().getBuffer(RenderType.lines());
|
||||
var buffer = bufferSource.getBuffer(RenderType.lines());
|
||||
var transform = transformStack.last().pose();
|
||||
var normal = transformStack.last().normal();
|
||||
if (faces.contains(NORTH) || faces.contains(WEST)) line(buffer, transform, normal, 0, 0, 0, UP);
|
||||
@ -75,6 +69,7 @@ public final class MonitorHighlightRenderer {
|
||||
if (faces.contains(EAST) || faces.contains(UP)) line(buffer, transform, normal, 1, 1, 0, SOUTH);
|
||||
|
||||
transformStack.popPose();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void line(VertexConsumer buffer, Matrix4f transform, Matrix3f normal, float x, float y, float z, Direction direction) {
|
||||
|
@ -14,15 +14,13 @@ import net.minecraft.client.renderer.RenderStateShard;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.ShaderInstance;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RegisterShadersEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class RenderTypes {
|
||||
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
|
||||
|
||||
@ -62,11 +60,10 @@ public class RenderTypes {
|
||||
return GameRenderer.getRendertypeTextShader();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerShaders(RegisterShadersEvent event) throws IOException {
|
||||
event.registerShader(
|
||||
public static void registerShaders(ResourceManager resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
|
||||
load.accept(
|
||||
new MonitorTextureBufferShader(
|
||||
event.getResourceManager(),
|
||||
resources,
|
||||
new ResourceLocation(ComputerCraft.MOD_ID, "monitor_tbo"),
|
||||
MONITOR_TBO.format()
|
||||
),
|
||||
|
@ -5,18 +5,22 @@
|
||||
*/
|
||||
package dan200.computercraft.client.sound;
|
||||
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
class DfpwmStream implements AudioStream {
|
||||
private static final int PREC = 10;
|
||||
@ -26,6 +30,23 @@ class DfpwmStream implements AudioStream {
|
||||
|
||||
private final Queue<ByteBuffer> buffers = new ArrayDeque<>(2);
|
||||
|
||||
/**
|
||||
* The {@link Channel} which this sound is playing on.
|
||||
*
|
||||
* @see SpeakerInstance#pushAudio(ByteBuf)
|
||||
*/
|
||||
@Nullable
|
||||
Channel channel;
|
||||
|
||||
/**
|
||||
* The underlying {@link SoundEngine} executor.
|
||||
*
|
||||
* @see SpeakerInstance#pushAudio(ByteBuf)
|
||||
* @see SoundEngine#executor
|
||||
*/
|
||||
@Nullable
|
||||
Executor executor;
|
||||
|
||||
private int charge = 0; // q
|
||||
private int strength = 0; // s
|
||||
private int lowPassCharge;
|
||||
|
@ -6,6 +6,7 @@
|
||||
package dan200.computercraft.client.sound;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@ -32,9 +33,11 @@ public class SpeakerInstance {
|
||||
currentStream.push(buffer);
|
||||
|
||||
// If we've got nothing left in the buffer, enqueue an additional one just in case.
|
||||
if (exhausted && sound != null && sound.stream == stream && sound.channel != null) {
|
||||
sound.executor.execute(() -> {
|
||||
if (!sound.channel.stopped()) sound.channel.pumpBuffers(1);
|
||||
if (exhausted && sound != null && sound.stream == stream && stream.channel != null && stream.executor != null) {
|
||||
var actualStream = sound.stream;
|
||||
stream.executor.execute(() -> {
|
||||
var channel = Nullability.assertNonNull(actualStream.channel);
|
||||
if (!channel.stopped()) channel.pumpBuffers(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,10 @@
|
||||
*/
|
||||
package dan200.computercraft.client.sound;
|
||||
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.sound.PlayStreamingSourceEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -18,17 +17,15 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* Maps speakers source IDs to a {@link SpeakerInstance}.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class SpeakerManager {
|
||||
private static final Map<UUID, SpeakerInstance> sounds = new ConcurrentHashMap<>();
|
||||
|
||||
@SubscribeEvent
|
||||
public static void playStreaming(PlayStreamingSourceEvent event) {
|
||||
if (!(event.getSound() instanceof SpeakerSound sound) || sound.stream == null) return;
|
||||
public static void onPlayStreaming(SoundEngine engine, Channel channel, AudioStream stream) {
|
||||
if (!(stream instanceof DfpwmStream dfpwmStream)) return;
|
||||
|
||||
// Associate the sound with the current channel, so SpeakerInstance.pushAudio can queue audio immediately.
|
||||
sound.channel = event.getChannel();
|
||||
sound.executor = event.getEngine().executor;
|
||||
// Associate the stream with the current channel, so SpeakerInstance.pushAudio can queue audio immediately.
|
||||
dfpwmStream.channel = channel;
|
||||
dfpwmStream.executor = engine.executor;
|
||||
}
|
||||
|
||||
public static SpeakerInstance getSound(UUID source) {
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
package dan200.computercraft.client.sound;
|
||||
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import net.minecraft.client.resources.sounds.AbstractSoundInstance;
|
||||
import net.minecraft.client.resources.sounds.Sound;
|
||||
@ -19,11 +18,8 @@ import net.minecraft.world.entity.Entity;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class SpeakerSound extends AbstractSoundInstance implements TickableSoundInstance {
|
||||
Channel channel;
|
||||
Executor executor;
|
||||
DfpwmStream stream;
|
||||
|
||||
private Entity entity;
|
||||
@ -69,4 +65,8 @@ public class SpeakerSound extends AbstractSoundInstance implements TickableSound
|
||||
public CompletableFuture<AudioStream> getStream(@Nonnull SoundBufferLibrary soundBuffers, @Nonnull Sound sound, boolean looping) {
|
||||
return stream != null ? CompletableFuture.completedFuture(stream) : super.getStream(soundBuffers, sound, looping);
|
||||
}
|
||||
|
||||
public AudioStream getStream() {
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
@ -7,57 +7,52 @@ package dan200.computercraft.shared;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.core.apis.http.NetworkUtils;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.ResourceMount;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.computer.metrics.ComputerMBean;
|
||||
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorWatcher;
|
||||
import dan200.computercraft.shared.util.DropConsumer;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
|
||||
import net.minecraft.world.level.storage.loot.LootPool;
|
||||
import net.minecraft.world.level.storage.loot.entries.LootTableReference;
|
||||
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
|
||||
import net.minecraftforge.event.*;
|
||||
import net.minecraftforge.event.server.ServerStartingEvent;
|
||||
import net.minecraftforge.event.server.ServerStoppedEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Miscellaneous hooks which are present on the client and server.
|
||||
* Event listeners for server/common code.
|
||||
* <p>
|
||||
* These should possibly be refactored into separate classes at some point, but are fine here for now.
|
||||
*
|
||||
* @see dan200.computercraft.client.ClientHooks For client-specific ones.
|
||||
* All event handlers should be defined in this class, and then invoked from a loader-specific event handler. This means
|
||||
* it's much easier to ensure that each hook is called in all loader source sets.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID)
|
||||
public final class CommonHooks {
|
||||
private CommonHooks() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) {
|
||||
ServerContext.get(ServerLifecycleHooks.getCurrentServer()).tick();
|
||||
}
|
||||
public static void onServerTickStart(MinecraftServer server) {
|
||||
ServerContext.get(server).tick();
|
||||
TickScheduler.tick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRegisterCommand(RegisterCommandsEvent event) {
|
||||
CommandComputerCraft.register(event.getDispatcher());
|
||||
public static void onServerTickEnd() {
|
||||
MonitorWatcher.onTick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerStarting(ServerStartingEvent event) {
|
||||
var server = event.getServer();
|
||||
public static void onServerStarting(MinecraftServer server) {
|
||||
if (server instanceof DedicatedServer dediServer && dediServer.getProperties().enableJmxMonitoring) {
|
||||
ComputerMBean.register();
|
||||
}
|
||||
@ -67,8 +62,7 @@ public final class CommonHooks {
|
||||
ComputerMBean.start(server);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerStopped(ServerStoppedEvent event) {
|
||||
public static void onServerStopped() {
|
||||
resetState();
|
||||
}
|
||||
|
||||
@ -78,6 +72,10 @@ public final class CommonHooks {
|
||||
NetworkUtils.reset();
|
||||
}
|
||||
|
||||
public static void onChunkWatch(LevelChunk chunk, ServerPlayer player) {
|
||||
MonitorWatcher.onWatch(chunk, player);
|
||||
}
|
||||
|
||||
public static final ResourceLocation LOOT_TREASURE_DISK = new ResourceLocation(ComputerCraft.MOD_ID, "treasure_disk");
|
||||
|
||||
private static final Set<ResourceLocation> TABLES = new HashSet<>(Arrays.asList(
|
||||
@ -93,32 +91,26 @@ public final class CommonHooks {
|
||||
BuiltInLootTables.VILLAGE_CARTOGRAPHER
|
||||
));
|
||||
|
||||
@SubscribeEvent
|
||||
public static void lootLoad(LootTableLoadEvent event) {
|
||||
var name = event.getName();
|
||||
if (!name.getNamespace().equals("minecraft") || !TABLES.contains(name)) return;
|
||||
|
||||
event.getTable().addPool(LootPool.lootPool()
|
||||
public static @Nullable LootPool.Builder getExtraLootPool(ResourceLocation lootTable) {
|
||||
if (!lootTable.getNamespace().equals("minecraft") || !TABLES.contains(lootTable)) return null;
|
||||
|
||||
return LootPool.lootPool()
|
||||
.add(LootTableReference.lootTableReference(LOOT_TREASURE_DISK))
|
||||
.setRolls(ConstantValue.exactly(1))
|
||||
.name("computercraft_treasure")
|
||||
.build());
|
||||
.setRolls(ConstantValue.exactly(1));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onAddReloadListeners(AddReloadListenerEvent event) {
|
||||
event.addListener(ResourceMount.RELOAD_LISTENER);
|
||||
event.addListener(TurtleUpgrades.instance());
|
||||
event.addListener(PocketUpgrades.instance());
|
||||
public static void onDatapackReload(BiConsumer<String, PreparableReloadListener> addReload) {
|
||||
addReload.accept("mounts", ResourceMount.RELOAD_LISTENER);
|
||||
addReload.accept("turtle_upgrades", TurtleUpgrades.instance());
|
||||
addReload.accept("pocket_upgrades", PocketUpgrades.instance());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onDatapackSync(OnDatapackSyncEvent event) {
|
||||
var packet = new UpgradesLoadedMessage();
|
||||
if (event.getPlayer() == null) {
|
||||
PlatformHelper.get().sendToAllPlayers(packet, event.getPlayerList().getServer());
|
||||
} else {
|
||||
PlatformHelper.get().sendToPlayer(packet, event.getPlayer());
|
||||
}
|
||||
public static boolean onEntitySpawn(Entity entity) {
|
||||
return DropConsumer.onEntitySpawn(entity);
|
||||
}
|
||||
|
||||
public static boolean onLivingDrop(Entity entity, ItemStack stack) {
|
||||
return DropConsumer.onLivingDrop(entity, stack);
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,8 @@ import dan200.computercraft.core.apis.http.options.Action;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
import net.minecraftforge.fml.event.config.ModConfigEvent;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.filter.MarkerFilter;
|
||||
@ -28,7 +25,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public final class Config {
|
||||
private static final int MODEM_MAX_RANGE = 100000;
|
||||
|
||||
@ -422,19 +418,9 @@ public final class Config {
|
||||
ComputerCraft.uploadNagDelay = uploadNagDelay.get();
|
||||
}
|
||||
|
||||
private static void sync(ModConfig config) {
|
||||
public static void sync(ModConfig config) {
|
||||
if (!config.getModId().equals(ComputerCraft.MOD_ID)) return;
|
||||
if (config.getType() == ModConfig.Type.SERVER) syncServer();
|
||||
if (config.getType() == ModConfig.Type.CLIENT) syncClient();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void sync(ModConfigEvent.Loading event) {
|
||||
sync(event.getConfig());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void sync(ModConfigEvent.Reloading event) {
|
||||
sync(event.getConfig());
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ package dan200.computercraft.shared;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
|
||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
|
||||
@ -16,13 +18,20 @@ import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem;
|
||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
|
||||
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||
import dan200.computercraft.shared.util.CapabilityProvider;
|
||||
import dan200.computercraft.shared.util.SidedCapabilityProvider;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.event.*;
|
||||
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingDropsEvent;
|
||||
import net.minecraftforge.event.level.ChunkWatchEvent;
|
||||
import net.minecraftforge.event.server.ServerStartingEvent;
|
||||
import net.minecraftforge.event.server.ServerStoppedEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
@ -31,8 +40,54 @@ import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
import static net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER;
|
||||
|
||||
/**
|
||||
* Forge-specific dispatch for {@link CommonHooks}.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID)
|
||||
public class ForgeCommonHooks {
|
||||
@SubscribeEvent
|
||||
public static void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
switch (event.phase) {
|
||||
case START -> CommonHooks.onServerTickStart(event.getServer());
|
||||
case END -> CommonHooks.onServerTickEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerStarting(ServerStartingEvent event) {
|
||||
CommonHooks.onServerStarting(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerStopped(ServerStoppedEvent event) {
|
||||
CommonHooks.onServerStopped();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRegisterCommand(RegisterCommandsEvent event) {
|
||||
CommandComputerCraft.register(event.getDispatcher());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onChunkWatch(ChunkWatchEvent.Watch event) {
|
||||
CommonHooks.onChunkWatch(event.getChunk(), event.getPlayer());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onAddReloadListeners(AddReloadListenerEvent event) {
|
||||
CommonHooks.onDatapackReload((id, listener) -> event.addListener(listener));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onDatapackSync(OnDatapackSyncEvent event) {
|
||||
var packet = new UpgradesLoadedMessage();
|
||||
if (event.getPlayer() == null) {
|
||||
PlatformHelper.get().sendToAllPlayers(packet, event.getPlayerList().getServer());
|
||||
} else {
|
||||
PlatformHelper.get().sendToPlayer(packet, event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation PERIPHERAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "peripheral");
|
||||
private static final ResourceLocation WIRED_ELEMENT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_node");
|
||||
private static final ResourceLocation INVENTORY = new ResourceLocation(ComputerCraftAPI.MOD_ID, "inventory");
|
||||
@ -83,4 +138,20 @@ public class ForgeCommonHooks {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, () -> new CommandBlockPeripheral(commandBlock));
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void lootLoad(LootTableLoadEvent event) {
|
||||
var pool = CommonHooks.getExtraLootPool(event.getName());
|
||||
if (pool != null) event.getTable().addPool(pool.build());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
public static void onEntitySpawn(EntityJoinLevelEvent event) {
|
||||
if (CommonHooks.onEntitySpawn(event.getEntity())) event.setCanceled(true);
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOW)
|
||||
public static void onLivingDrops(LivingDropsEvent event) {
|
||||
event.getDrops().removeIf(itemEntity -> CommonHooks.onLivingDrop(event.getEntity(), itemEntity.getItem()));
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared;
|
||||
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.detail.IDetailProvider;
|
||||
import dan200.computercraft.api.detail.VanillaDetailRegistries;
|
||||
import dan200.computercraft.api.media.IMedia;
|
||||
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
|
||||
@ -99,6 +100,12 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Registers ComputerCraft's registry entries and additional objects, such as {@link CauldronInteraction}s and
|
||||
* {@link IDetailProvider}s
|
||||
* <p>
|
||||
* The functions in this class should be called from a loader-specific class.
|
||||
*/
|
||||
public final class ModRegistry {
|
||||
private static final CreativeModeTab mainItemGroup = new CreativeTabMain();
|
||||
|
||||
@ -354,6 +361,9 @@ public final class ModRegistry {
|
||||
public static final RegistryEntry<ImpostorShapelessRecipe.Serializer> IMPOSTOR_SHAPELESS = REGISTRY.register("impostor_shapeless", ImpostorShapelessRecipe.Serializer::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any objects which don't have to be done on the main thread.
|
||||
*/
|
||||
public static void register() {
|
||||
Blocks.REGISTRY.register();
|
||||
BlockEntities.REGISTRY.register();
|
||||
@ -379,6 +389,9 @@ public final class ModRegistry {
|
||||
VanillaDetailRegistries.BLOCK_IN_WORLD.addProvider(BlockData::fill);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any objects which must be done on the main thread.
|
||||
*/
|
||||
public static void registerMainThread() {
|
||||
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_NORMAL.get(), ItemTurtle.CAULDRON_INTERACTION);
|
||||
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_ADVANCED.get(), ItemTurtle.CAULDRON_INTERACTION);
|
||||
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.command;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ClientChatEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Basic client-side commands.
|
||||
* <p>
|
||||
* Simply hooks into client chat messages and intercepts matching strings.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
|
||||
public final class ClientCommands {
|
||||
public static final String OPEN_COMPUTER = "/computercraft open-computer ";
|
||||
|
||||
private ClientCommands() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClientSendMessage(ClientChatEvent event) {
|
||||
// Emulate the command on the client side
|
||||
if (event.getMessage().startsWith(OPEN_COMPUTER)) {
|
||||
MinecraftServer server = Minecraft.getInstance().getSingleplayerServer();
|
||||
if (server == null) return;
|
||||
|
||||
event.setCanceled(true);
|
||||
|
||||
var idStr = event.getMessage().substring(OPEN_COMPUTER.length()).trim();
|
||||
int id;
|
||||
try {
|
||||
id = Integer.parseInt(idStr);
|
||||
} catch (NumberFormatException ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
var file = new File(ServerContext.get(server).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) return;
|
||||
|
||||
Util.getPlatform().openFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -51,6 +51,7 @@ import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public final class CommandComputerCraft {
|
||||
public static final UUID SYSTEM_UUID = new UUID(0, 0);
|
||||
public static final String OPEN_COMPUTER = "/computercraft open-computer ";
|
||||
|
||||
private CommandComputerCraft() {
|
||||
}
|
||||
@ -310,7 +311,7 @@ public final class CommandComputerCraft {
|
||||
|
||||
return link(
|
||||
text("\u270E"),
|
||||
ClientCommands.OPEN_COMPUTER + id,
|
||||
OPEN_COMPUTER + id,
|
||||
translate("commands.computercraft.dump.open_path")
|
||||
);
|
||||
}
|
||||
|
@ -12,13 +12,15 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.MediaProviders;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.network.client.PlayRecordClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.util.DefaultInventory;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import dan200.computercraft.shared.util.RecordUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.*;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
@ -29,6 +31,7 @@ import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -408,14 +411,18 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
|
||||
var contents = getDiskMedia();
|
||||
var record = contents != null ? contents.getAudio(diskStack) : null;
|
||||
if (record != null) {
|
||||
RecordUtil.playRecord(record, contents.getAudioTitle(diskStack), getLevel(), getBlockPos());
|
||||
playRecord(new PlayRecordClientMessage(getBlockPos(), record, contents.getAudioTitle(diskStack)));
|
||||
} else {
|
||||
RecordUtil.playRecord(null, null, getLevel(), getBlockPos());
|
||||
stopRecord();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopRecord() {
|
||||
RecordUtil.playRecord(null, null, getLevel(), getBlockPos());
|
||||
playRecord(new PlayRecordClientMessage(getBlockPos()));
|
||||
}
|
||||
|
||||
private void playRecord(PlayRecordClientMessage message) {
|
||||
PlatformHelper.get().sendToAllAround(message, (ServerLevel) getLevel(), Vec3.atCenterOf(getBlockPos()), 64);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,15 +10,12 @@ import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.network.client.MonitorClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.level.ChunkWatchEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID)
|
||||
public final class MonitorWatcher {
|
||||
private static final Queue<TileMonitor> watching = new ArrayDeque<>();
|
||||
|
||||
@ -33,27 +30,23 @@ public final class MonitorWatcher {
|
||||
watching.add(monitor);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onWatch(ChunkWatchEvent.Watch event) {
|
||||
public static void onWatch(LevelChunk chunk, ServerPlayer player) {
|
||||
// Find all origin monitors who are not already on the queue and send the
|
||||
// monitor data to the player.
|
||||
for (var te : event.getChunk().getBlockEntities().values()) {
|
||||
for (var te : chunk.getBlockEntities().values()) {
|
||||
if (!(te instanceof TileMonitor monitor)) continue;
|
||||
|
||||
var serverMonitor = getMonitor(monitor);
|
||||
if (serverMonitor == null || monitor.enqueued) continue;
|
||||
|
||||
var state = getState(monitor, serverMonitor);
|
||||
PlatformHelper.get().sendToPlayer(new MonitorClientMessage(monitor.getBlockPos(), state), event.getPlayer());
|
||||
PlatformHelper.get().sendToPlayer(new MonitorClientMessage(monitor.getBlockPos(), state), player);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTick(TickEvent.ServerTickEvent event) {
|
||||
public static void onTick() {
|
||||
// Find all enqueued monitors and send their contents to all nearby players.
|
||||
|
||||
if (event.phase != TickEvent.Phase.END) return;
|
||||
|
||||
var limit = ComputerCraft.monitorBandwidth;
|
||||
var obeyLimit = limit > 0;
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@ -13,17 +12,11 @@ import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingDropsEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID)
|
||||
public final class DropConsumer {
|
||||
private DropConsumer() {
|
||||
}
|
||||
@ -72,22 +65,21 @@ public final class DropConsumer {
|
||||
if (!remaining.isEmpty()) remainingDrops.add(remaining);
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
public static void onEntitySpawn(EntityJoinLevelEvent event) {
|
||||
public static boolean onEntitySpawn(Entity entity) {
|
||||
// Capture any nearby item spawns
|
||||
if (dropWorld == event.getLevel() && event.getEntity() instanceof ItemEntity
|
||||
&& dropBounds.contains(event.getEntity().position())) {
|
||||
handleDrops(((ItemEntity) event.getEntity()).getItem());
|
||||
event.setCanceled(true);
|
||||
if (dropWorld == entity.getLevel() && entity instanceof ItemEntity
|
||||
&& dropBounds.contains(entity.position())) {
|
||||
handleDrops(((ItemEntity) entity).getItem());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOW)
|
||||
public static void onLivingDrops(LivingDropsEvent drops) {
|
||||
if (dropEntity == null || drops.getEntity() != dropEntity) return;
|
||||
public static boolean onLivingDrop(Entity entity, ItemStack stack) {
|
||||
if (dropEntity == null || entity != dropEntity) return false;
|
||||
|
||||
for (var drop : drops.getDrops()) handleDrops(drop.getItem());
|
||||
drops.getDrops().clear();
|
||||
drops.setCanceled(true);
|
||||
handleDrops(stack);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -6,16 +6,10 @@
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
/**
|
||||
* A monotonically increasing clock which accounts for the game being paused.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public final class PauseAwareTimer {
|
||||
private static boolean paused;
|
||||
private static long pauseTime;
|
||||
@ -28,11 +22,7 @@ public final class PauseAwareTimer {
|
||||
return (paused ? pauseTime : Util.getNanos()) - pauseOffset;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void tick(TickEvent.RenderTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
|
||||
var isPaused = Minecraft.getInstance().isPaused();
|
||||
public static void tick(boolean isPaused) {
|
||||
if (isPaused == paused) return;
|
||||
|
||||
if (isPaused) {
|
||||
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.client.PlayRecordClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public final class RecordUtil {
|
||||
private RecordUtil() {
|
||||
}
|
||||
|
||||
public static void playRecord(SoundEvent record, String recordInfo, Level world, BlockPos pos) {
|
||||
NetworkMessage packet = record != null ? new PlayRecordClientMessage(pos, record, recordInfo) : new PlayRecordClientMessage(pos);
|
||||
PlatformHelper.get().sendToAllAround(packet, (ServerLevel) world, Vec3.atCenterOf(pos), 64);
|
||||
}
|
||||
}
|
@ -5,14 +5,10 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
@ -23,7 +19,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* <p>
|
||||
* We use this when modems and other peripherals change a block in a different thread.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraft.MOD_ID)
|
||||
public final class TickScheduler {
|
||||
private TickScheduler() {
|
||||
}
|
||||
@ -35,10 +30,7 @@ public final class TickScheduler {
|
||||
if (world != null && !world.isClientSide && !token.scheduled.getAndSet(true)) toTick.add(token);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void tick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
|
||||
public static void tick() {
|
||||
Token token;
|
||||
while ((token = toTick.poll()) != null) {
|
||||
token.scheduled.set(false);
|
||||
|
Loading…
Reference in New Issue
Block a user