Merge branch 'Creators-of-Create:mc1.18/dev' into new-issue-templates

This commit is contained in:
TropheusJ 2023-10-23 19:24:16 -04:00 committed by GitHub
commit 41fb43adb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 597 additions and 48 deletions

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -582,8 +582,8 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
5616dda664dd106d576848124fc0fc1de18d0fd3 assets/create/blockstates/yellow_valve_handle.json
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
fb5edeb33c43fb1aa36cfe84e376da287ae23b51 assets/create/lang/en_ud.json
eac32f8a9ed3c1b652916191c96c0ee446fd97ca assets/create/lang/en_us.json
d09a8a181fa472e6ae66bdd8d937d1464aee102f assets/create/lang/en_ud.json
71b5b55d73d5bd7fb39bd352338d9e1ad7184ea9 assets/create/lang/en_us.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json

View File

@ -858,6 +858,8 @@
"create.clipboard.pasted_to": "%1$s o\u0287 sbu\u0131\u0287\u0287\u01DDs p\u01DD\u0131\u05DFdd\u2C6F",
"create.clipboard.to_copy": "sbu\u0131\u0287\u0287\u01DDs \u028Edo\u0186 o\u0287 %1$s",
"create.clipboard.to_paste": "sbu\u0131\u0287\u0287\u01DDs \u01DD\u0287s\u0250\u0500 o\u0287 %1$s",
"create.command.debuginfo.saved_to_clipboard": "\u02D9p\u0279\u0250oqd\u0131\u05DF\u0254 \u0279no\u028E o\u0287 p\u01DD\u0131do\u0254 u\u01DD\u01DDq s\u0250\u0265 uo\u0131\u0287\u0250\u026F\u0279o\u025Fu\u0131 bnq\u01DD\u15E1",
"create.command.debuginfo.sending": "\u02D9\u02D9\u02D9uo\u0131\u0287\u0250\u026F\u0279o\u025Fu\u0131 bnq\u01DDp bu\u0131\u0287\u0254\u01DD\u05DF\u05DFo\u0186",
"create.command.killTPSCommand": "sd\u0287\u05DF\u05DF\u0131\u029E",
"create.command.killTPSCommand.argument.tickTime": "\u01DD\u026F\u0131\u27D8\u029E\u0254\u0131\u0287",
"create.command.killTPSCommand.status.slowed_by.0": "o: s\u026F %s \u028Eq p\u01DD\u028Do\u05DFs \u028E\u05DF\u0287u\u01DD\u0279\u0279n\u0254 s\u0131 \u029E\u0254\u0131\u0287 \u0279\u01DD\u028C\u0279\u01DDS :]\u01DD\u0287\u0250\u01DD\u0279\u0186[",

View File

@ -858,6 +858,8 @@
"create.clipboard.pasted_to": "Applied settings to %1$s",
"create.clipboard.to_copy": "%1$s to Copy settings",
"create.clipboard.to_paste": "%1$s to Paste settings",
"create.command.debuginfo.saved_to_clipboard": "Debug information has been copied to your clipboard.",
"create.command.debuginfo.sending": "Collecting debug information...",
"create.command.killTPSCommand": "killtps",
"create.command.killTPSCommand.argument.tickTime": "tickTime",
"create.command.killTPSCommand.status.slowed_by.0": "[Create]: Server tick is currently slowed by %s ms :o",

View File

@ -93,6 +93,8 @@ import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.infrastructure.command.HighlightPacket;
import com.simibubi.create.infrastructure.command.SConfigureConfigPacket;
import com.simibubi.create.infrastructure.debugInfo.ServerDebugInfoPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
@ -203,7 +205,7 @@ public enum AllPackets {
CONTRAPTION_ACTOR_TOGGLE(ContraptionDisableActorPacket.class, ContraptionDisableActorPacket::new, PLAY_TO_CLIENT),
CONTRAPTION_COLLIDER_LOCK(ContraptionColliderLockPacket.class, ContraptionColliderLockPacket::new, PLAY_TO_CLIENT),
ATTACHED_COMPUTER(AttachedComputerPacket.class, AttachedComputerPacket::new, PLAY_TO_CLIENT),
SERVER_DEBUG_INFO(ServerDebugInfoPacket.class, ServerDebugInfoPacket::new, PLAY_TO_CLIENT)
;
public static final ResourceLocation CHANNEL_NAME = Create.asResource("main");

View File

@ -58,7 +58,7 @@ public class PortableStorageInterfaceBlock extends WrenchableDirectionalBlock
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction direction = context.getNearestLookingDirection();
if (context.getPlayer() != null && context.getPlayer()
.isSteppingCarefully())
.isShiftKeyDown())
direction = direction.getOpposite();
return defaultBlockState().setValue(FACING, direction.getOpposite());
}

View File

@ -56,7 +56,7 @@ public class ControlsBlock extends HorizontalDirectionalBlock implements IWrench
Player player = pContext.getPlayer();
state = state.setValue(FACING, horizontalDirection.getOpposite());
if (player != null && player.isSteppingCarefully())
if (player != null && player.isShiftKeyDown())
state = state.setValue(FACING, horizontalDirection);
return state;

View File

@ -121,7 +121,7 @@ public class SuperGlueSelectionHandler {
return;
}
boolean cancel = player.isSteppingCarefully();
boolean cancel = player.isShiftKeyDown();
if (cancel && firstPos == null)
return;
@ -201,7 +201,7 @@ public class SuperGlueSelectionHandler {
return true;
}
if (player.isSteppingCarefully()) {
if (player.isShiftKeyDown()) {
if (firstPos != null) {
discard();
return true;

View File

@ -316,7 +316,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos,
Player player) {
BlockState material = getMaterial(level, pos);
if (AllBlocks.COPYCAT_BASE.has(material) || player != null && player.isSteppingCarefully())
if (AllBlocks.COPYCAT_BASE.has(material) || player != null && player.isShiftKeyDown())
return new ItemStack(this);
return material.getCloneItemStack(target, level, pos, player);
}

View File

@ -121,7 +121,7 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc
return InteractionResult.SUCCESS;
}
if (AllItems.WRENCH.isIn(itemInHand) && !pPlayer.isSteppingCarefully()) {
if (AllItems.WRENCH.isIn(itemInHand) && !pPlayer.isShiftKeyDown()) {
if (GirderWrenchBehavior.handleClick(pLevel, pPos, pState, pHit))
return InteractionResult.sidedSuccess(pLevel.isClientSide);
return InteractionResult.FAIL;

View File

@ -44,7 +44,7 @@ public class GirderWrenchBehavior {
Player player = mc.player;
ItemStack heldItem = player.getMainHandItem();
if (player.isSteppingCarefully())
if (player.isShiftKeyDown())
return;
if (!AllBlocks.METAL_GIRDER.has(world.getBlockState(pos)))

View File

@ -18,7 +18,7 @@ public class LayeredBlock extends RotatedPillarBlock {
.relative(pContext.getClickedFace()
.getOpposite()));
if (placedOn.getBlock() == this && (pContext.getPlayer() == null || !pContext.getPlayer()
.isSteppingCarefully()))
.isShiftKeyDown()))
stateForPlacement = stateForPlacement.setValue(AXIS, placedOn.getValue(AXIS));
return stateForPlacement;
}

View File

@ -1,6 +1,6 @@
package com.simibubi.create.content.equipment.armor;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllTags.AllItemTags;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.EquipmentSlot;
@ -28,13 +28,13 @@ public final class NetheriteDivingHandler {
ItemStack to = event.getTo();
if (slot == EquipmentSlot.HEAD) {
if (AllItems.NETHERITE_DIVING_HELMET.isIn(to)) {
if (isNetheriteDivingHelmet(to)) {
setBit(entity, slot);
} else {
clearBit(entity, slot);
}
} else if (slot == EquipmentSlot.CHEST) {
if (AllItems.NETHERITE_BACKTANK.isIn(to) && BacktankUtil.hasAirRemaining(to)) {
if (isNetheriteBacktank(to) && BacktankUtil.hasAirRemaining(to)) {
setBit(entity, slot);
} else {
clearBit(entity, slot);
@ -48,6 +48,14 @@ public final class NetheriteDivingHandler {
}
}
public static boolean isNetheriteDivingHelmet(ItemStack stack) {
return stack.getItem() instanceof DivingHelmetItem && isNetheriteArmor(stack);
}
public static boolean isNetheriteBacktank(ItemStack stack) {
return stack.is(AllItemTags.PRESSURIZED_AIR_SOURCES.tag) && isNetheriteArmor(stack);
}
public static boolean isNetheriteArmor(ItemStack stack) {
return stack.getItem() instanceof ArmorItem armorItem && armorItem.getMaterial() == ArmorMaterials.NETHERITE;
}

View File

@ -87,7 +87,7 @@ public class ClipboardBlock extends FaceAttachedHorizontalDirectionalBlock
@Override
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand,
BlockHitResult pHit) {
if (pPlayer.isSteppingCarefully()) {
if (pPlayer.isShiftKeyDown()) {
breakAndCollect(pState, pLevel, pPos, pPlayer);
return InteractionResult.SUCCESS;
}

View File

@ -34,7 +34,7 @@ public class ClipboardBlockItem extends BlockItem {
Player player = context.getPlayer();
if (player == null)
return InteractionResult.PASS;
if (player.isSteppingCarefully())
if (player.isShiftKeyDown())
return super.useOn(context);
return use(context.getLevel(), player, context.getHand()).getResult();
}

View File

@ -141,7 +141,7 @@ public class ClipboardValueSettingsHandler {
Player player = event.getPlayer();
if (player != null && player.isSpectator())
return;
if (player.isSteppingCarefully())
if (player.isShiftKeyDown())
return;
if (!(world.getBlockEntity(pos) instanceof SmartBlockEntity smartBE))
return;

View File

@ -132,7 +132,7 @@ public class PumpBlock extends DirectionalKineticBlock
return toPlace;
if (bestConnectedDirection.getAxis() == targetDirection.getAxis())
return toPlace;
if (player.isSteppingCarefully() && bestConnectedDirection.getAxis() != targetDirection.getAxis())
if (player.isShiftKeyDown() && bestConnectedDirection.getAxis() != targetDirection.getAxis())
return toPlace;
return toPlace.setValue(FACING, bestConnectedDirection);

View File

@ -66,7 +66,7 @@ public class ValveHandleBlock extends HandCrankBlock {
return;
if (!player.mayBuild())
return;
if (AllItems.WRENCH.isIn(player.getItemInHand(event.getHand())) && player.isSteppingCarefully())
if (AllItems.WRENCH.isIn(player.getItemInHand(event.getHand())) && player.isShiftKeyDown())
return;
if (vhb.clicked(level, pos, blockState, player, event.getHand())) {
@ -94,7 +94,7 @@ public class ValveHandleBlock extends HandCrankBlock {
}
onBlockEntityUse(level, pos,
hcbe -> (hcbe instanceof ValveHandleBlockEntity vhbe) && vhbe.activate(player.isSteppingCarefully())
hcbe -> (hcbe instanceof ValveHandleBlockEntity vhbe) && vhbe.activate(player.isShiftKeyDown())
? InteractionResult.SUCCESS
: InteractionResult.PASS);
return true;

View File

@ -53,7 +53,7 @@ public class ItemVaultBlock extends Block implements IWrenchable, IBE<ItemVaultB
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
if (pContext.getPlayer() == null || !pContext.getPlayer()
.isSteppingCarefully()) {
.isShiftKeyDown()) {
BlockState placedOn = pContext.getLevel()
.getBlockState(pContext.getClickedPos()
.relative(pContext.getClickedFace()

View File

@ -54,7 +54,7 @@ public class ItemVaultItem extends BlockItem {
Player player = ctx.getPlayer();
if (player == null)
return;
if (player.isSteppingCarefully())
if (player.isShiftKeyDown())
return;
Direction face = ctx.getClickedFace();
ItemStack stack = ctx.getItemInHand();

View File

@ -35,7 +35,7 @@ public class ExperienceNuggetItem extends Item {
return InteractionResultHolder.consume(itemInHand);
}
int amountUsed = pPlayer.isSteppingCarefully() ? 1 : itemInHand.getCount();
int amountUsed = pPlayer.isShiftKeyDown() ? 1 : itemInHand.getCount();
int total = Mth.ceil(3f * amountUsed);
int maxOrbs = amountUsed == 1 ? 1 : 5;
int valuePer = Math.max(1, 1 + total / maxOrbs);

View File

@ -139,7 +139,7 @@ public class DisplayLinkBlock extends WrenchableDirectionalBlock implements IBE<
BlockHitResult pHit) {
if (pPlayer == null)
return InteractionResult.PASS;
if (pPlayer.isSteppingCarefully())
if (pPlayer.isShiftKeyDown())
return InteractionResult.PASS;
DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
() -> () -> withBlockEntityDo(pLevel, pPos, be -> this.displayScreen(be, pPlayer)));

View File

@ -57,7 +57,7 @@ public class DisplayLinkBlockItem extends BlockItem {
if (player == null)
return InteractionResult.FAIL;
if (player.isSteppingCarefully() && stack.hasTag()) {
if (player.isShiftKeyDown() && stack.hasTag()) {
if (level.isClientSide)
return InteractionResult.SUCCESS;
player.displayClientMessage(Lang.translateDirect("display_link.clear"), true);

View File

@ -85,7 +85,7 @@ public class SmartObserverBlock extends DirectedDirectionalBlock implements IBE<
if (preferredFacing == null) {
Direction facing = context.getNearestLookingDirection();
preferredFacing = context.getPlayer() != null && context.getPlayer()
.isSteppingCarefully() ? facing : facing.getOpposite();
.isShiftKeyDown() ? facing : facing.getOpposite();
}
if (preferredFacing.getAxis() == Axis.Y) {

View File

@ -123,7 +123,7 @@ public class ThresholdSwitchBlock extends DirectedDirectionalBlock implements IB
if (preferredFacing == null) {
Direction facing = context.getNearestLookingDirection();
preferredFacing = context.getPlayer() != null && context.getPlayer()
.isSteppingCarefully() ? facing : facing.getOpposite();
.isShiftKeyDown() ? facing : facing.getOpposite();
}
if (preferredFacing.getAxis() == Axis.Y) {

View File

@ -83,7 +83,7 @@ public class TrainRelocator {
return;
if (!player.position()
.closerThan(relocatingOrigin, 24) || player.isSteppingCarefully()) {
.closerThan(relocatingOrigin, 24) || player.isShiftKeyDown()) {
relocatingTrain = null;
player.displayClientMessage(Lang.translateDirect("train.relocate.abort")
.withStyle(ChatFormatting.RED), true);

View File

@ -113,7 +113,7 @@ public class StationBlock extends Block implements IBE<StationBlockEntity>, IWre
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand,
BlockHitResult pHit) {
if (pPlayer == null || pPlayer.isSteppingCarefully())
if (pPlayer == null || pPlayer.isShiftKeyDown())
return InteractionResult.PASS;
ItemStack itemInHand = pPlayer.getItemInHand(pHand);
if (AllItems.WRENCH.isIn(itemInHand))

View File

@ -126,7 +126,7 @@ public class CurvedTrackInteraction {
player.swing(InteractionHand.MAIN_HAND);
return true;
}
if (AllItems.WRENCH.isIn(heldItem) && player.isSteppingCarefully()) {
if (AllItems.WRENCH.isIn(heldItem) && player.isShiftKeyDown()) {
AllPackets.getChannel().sendToServer(new CurvedTrackDestroyPacket(result.blockEntity()
.getBlockPos(),
result.loc()

View File

@ -60,7 +60,7 @@ public class CurvedTrackSelectionPacket extends BlockEntityConfigurationPacket<T
.getItem(slot);
if (!(stack.getItem() instanceof TrackTargetingBlockItem))
return;
if (player.isSteppingCarefully() && stack.hasTag()) {
if (player.isShiftKeyDown() && stack.hasTag()) {
player.displayClientMessage(Lang.translateDirect("track_target.clear"), true);
stack.setTag(null);
AllSoundEvents.CONTROLLER_CLICK.play(player.level, null, pos, 1, .5f);

View File

@ -80,7 +80,7 @@ public class TrackBlockItem extends BlockItem {
}
return super.useOn(pContext);
} else if (player.isSteppingCarefully()) {
} else if (player.isShiftKeyDown()) {
if (!level.isClientSide) {
player.displayClientMessage(Lang.translateDirect("track.selection_cleared"), true);
stack.setTag(null);

View File

@ -65,7 +65,7 @@ public class TrackTargetingBlockItem extends BlockItem {
if (player == null)
return InteractionResult.FAIL;
if (player.isSteppingCarefully() && stack.hasTag()) {
if (player.isShiftKeyDown() && stack.hasTag()) {
if (level.isClientSide)
return InteractionResult.SUCCESS;
player.displayClientMessage(Lang.translateDirect("track_target.clear"), true);

View File

@ -3,7 +3,6 @@ package com.simibubi.create.foundation.events;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllFluids;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllPackets;
import com.simibubi.create.Create;
import com.simibubi.create.CreateClient;
@ -19,6 +18,7 @@ import com.simibubi.create.content.decoration.girder.GirderWrenchBehavior;
import com.simibubi.create.content.equipment.armor.BacktankArmorLayer;
import com.simibubi.create.content.equipment.armor.DivingHelmetItem;
import com.simibubi.create.content.equipment.armor.NetheriteBacktankFirstPersonRenderer;
import com.simibubi.create.content.equipment.armor.NetheriteDivingHandler;
import com.simibubi.create.content.equipment.blueprint.BlueprintOverlayRenderer;
import com.simibubi.create.content.equipment.clipboard.ClipboardValueSettingsHandler;
import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripRenderHandler;
@ -316,7 +316,7 @@ public class ClientEvents {
event.scaleFarPlaneDistance(6.25f);
event.setCanceled(true);
return;
} else if (FluidHelper.isLava(fluid) && AllItems.NETHERITE_DIVING_HELMET.isIn(divingHelmet)) {
} else if (FluidHelper.isLava(fluid) && NetheriteDivingHandler.isNetheriteDivingHelmet(divingHelmet)) {
event.setNearPlaneDistance(-4.0f);
event.setFarPlaneDistance(20.0f);
event.setCanceled(true);

View File

@ -0,0 +1,24 @@
package com.simibubi.create.foundation.mixin.accessor;
import net.minecraft.SystemReport;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(SystemReport.class)
public interface SystemReportAccessor {
@Accessor
static String getOPERATING_SYSTEM() {
throw new AssertionError();
}
@Accessor
static String getJAVA_VERSION() {
throw new AssertionError();
}
@Accessor
Map<String, String> getEntries();
}

View File

@ -30,6 +30,7 @@ public class AllCommands {
.then(OverlayConfigCommand.register())
.then(DumpRailwaysCommand.register())
.then(FixLightingCommand.register())
.then(DebugInfoCommand.register())
.then(HighlightCommand.register())
.then(KillTrainCommand.register())
.then(PassengerCommand.register())
@ -39,6 +40,7 @@ public class AllCommands {
.then(CloneCommand.register())
.then(GlueCommand.register())
// utility
.then(util);

View File

@ -0,0 +1,29 @@
package com.simibubi.create.infrastructure.command;
import static net.minecraft.commands.Commands.literal;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.AllPackets;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.infrastructure.debugInfo.ServerDebugInfoPacket;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.PacketDistributor;
public class DebugInfoCommand {
public static ArgumentBuilder<CommandSourceStack, ?> register() {
return literal("debuginfo").executes(ctx -> {
CommandSourceStack source = ctx.getSource();
ServerPlayer player = source.getPlayerOrException();
Lang.translate("command.debuginfo.sending")
.sendChat(player);
AllPackets.getChannel()
.send(PacketDistributor.PLAYER.with(() -> player), new ServerDebugInfoPacket(player));
return Command.SINGLE_SUCCESS;
});
}
}

View File

@ -0,0 +1,162 @@
package com.simibubi.create.infrastructure.debugInfo;
import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.Backend;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.mixin.accessor.SystemReportAccessor;
import com.simibubi.create.infrastructure.debugInfo.element.DebugInfoSection;
import net.minecraft.SharedConstants;
import net.minecraft.SystemReport;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import com.simibubi.create.infrastructure.debugInfo.element.InfoElement;
import com.simibubi.create.infrastructure.debugInfo.element.InfoEntry;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.forgespi.language.IModInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.mojang.blaze3d.platform.GlUtil;
/**
* Allows for providing easily accessible debugging information.
* This info can be retrieved with the "/create debuginfo" command.
* This command copies all information to the clipboard, formatted for a GitHub issue.
* Addons are welcome to add their own sections. Registration must occur synchronously.
*/
public class DebugInformation {
private static final List<DebugInfoSection> client = new ArrayList<>();
private static final List<DebugInfoSection> server = new ArrayList<>();
private static final ImmutableMap<String, String> mcSystemInfo = Util.make(() -> {
SystemReport systemReport = new SystemReport();
SystemReportAccessor access = (SystemReportAccessor) systemReport;
return ImmutableMap.copyOf(access.getEntries());
});
public static void registerClientInfo(DebugInfoSection section) {
client.add(section);
}
public static void registerServerInfo(DebugInfoSection section) {
server.add(section);
}
public static void registerBothInfo(DebugInfoSection section) {
registerClientInfo(section);
registerServerInfo(section);
}
public static List<DebugInfoSection> getClientInfo() {
return client;
}
public static List<DebugInfoSection> getServerInfo() {
return server;
}
static {
DebugInfoSection.builder(Create.NAME)
.put("Mod Version", Create.VERSION)
.put("Forge Version", getVersionOfMod("forge"))
.put("Minecraft Version", SharedConstants.getCurrentVersion().getName())
.buildTo(DebugInformation::registerBothInfo);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
DebugInfoSection.builder("Graphics")
.put("Flywheel Version", Flywheel.getVersion().toString())
.put("Flywheel Backend", () -> Backend.getBackendType().toString())
.put("OpenGL Renderer", GlUtil::getRenderer)
.put("OpenGL Version", GlUtil::getOpenGLVersion)
.put("Graphics Mode", () -> Minecraft.getInstance().options.graphicsMode.toString())
.buildTo(DebugInformation::registerClientInfo);
});
DebugInfoSection.builder("System Information")
.put("Operating System", SystemReportAccessor.getOPERATING_SYSTEM())
.put("Java Version", SystemReportAccessor.getJAVA_VERSION())
.put("JVM Flags", getMcSystemInfo("JVM Flags"))
.put("Memory", () -> getMcSystemInfo("Memory"))
.put("CPU", getCpuInfo())
.putAll(listAllGraphicsCards())
.buildTo(DebugInformation::registerBothInfo);
DebugInfoSection.builder("Other Mods")
.putAll(listAllOtherMods())
.buildTo(DebugInformation::registerBothInfo);
}
public static String getVersionOfMod(String id) {
return ModList.get().getModContainerById(id)
.map(mod -> mod.getModInfo().getVersion().toString())
.orElse("None");
}
public static Collection<InfoElement> listAllOtherMods() {
List<InfoElement> mods = new ArrayList<>();
ModList.get().forEachModContainer((id, mod) -> {
if (!id.equals(Create.ID) && !id.equals("forge") && !id.equals("minecraft") && !id.equals("flywheel")) {
IModInfo info = mod.getModInfo();
String name = info.getDisplayName();
String version = info.getVersion().toString();
mods.add(new InfoEntry(name, version));
}
});
return mods;
}
public static Collection<InfoElement> listAllGraphicsCards() {
List<InfoElement> cards = new ArrayList<>();
for (int i = 0; i < 10; i++) { // there won't be more than 10, right? right??
String name = getMcSystemInfo("Graphics card #" + i + " name");
String vendor = getMcSystemInfo("Graphics card #" + i + " vendor");
String vram = getMcSystemInfo("Graphics card #" + i + " VRAM (MB)");
if (name == null || vendor == null || vram == null)
break;
String key = "Graphics card #" + i;
String value = String.format("%s (%s); %s MB of VRAM", name, vendor, vram);
cards.add(new InfoEntry(key, value));
}
return cards.isEmpty() ? List.of(new InfoEntry("Graphics cards", "none")) : cards;
}
public static String getCpuInfo() {
String name = tryTrim(getMcSystemInfo("Processor Name"));
String freq = getMcSystemInfo("Frequency (GHz)");
String sockets = getMcSystemInfo("Number of physical packages");
String cores = getMcSystemInfo("Number of physical CPUs");
String threads = getMcSystemInfo("Number of logical CPUs");
return String.format("%s @ %s GHz; %s cores / %s threads on %s socket(s)", name, freq, cores, threads, sockets);
}
/**
* Get a system attribute provided by Minecraft.
* They can be found in the constructor of {@link SystemReport}.
*/
@Nullable
public static String getMcSystemInfo(String key) {
return mcSystemInfo.get(key);
}
public static String getIndent(int depth) {
return Stream.generate(() -> "\t").limit(depth).collect(Collectors.joining());
}
@Nullable
public static String tryTrim(@Nullable String s) {
return s == null ? null : s.trim();
}
}

View File

@ -0,0 +1,32 @@
package com.simibubi.create.infrastructure.debugInfo;
import java.util.Objects;
import net.minecraft.world.entity.player.Player;
import javax.annotation.Nullable;
/**
* A supplier of debug information. May be queried on the client or server.
*/
@FunctionalInterface
public interface InfoProvider {
/**
* @param player the player requesting the data. May be null
*/
@Nullable
String getInfo(@Nullable Player player);
default String getInfoSafe(Player player) {
try {
return Objects.toString(getInfo(player));
} catch (Throwable t) {
StringBuilder builder = new StringBuilder("Error getting information!");
builder.append(' ').append(t.getMessage());
for (StackTraceElement element : t.getStackTrace()) {
builder.append('\n').append("\t").append(element.toString());
}
return builder.toString();
}
}
}

View File

@ -0,0 +1,91 @@
package com.simibubi.create.infrastructure.debugInfo;
import java.util.List;
import java.util.Objects;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import com.simibubi.create.foundation.utility.DyeHelper;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.infrastructure.debugInfo.element.DebugInfoSection;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.DyeColor;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.NetworkEvent;
public class ServerDebugInfoPacket extends SimplePacketBase {
private final List<DebugInfoSection> serverInfo;
private final Player player;
public ServerDebugInfoPacket(Player player) {
this.serverInfo = DebugInformation.getServerInfo();
this.player = player;
}
public ServerDebugInfoPacket(FriendlyByteBuf buffer) {
this.serverInfo = buffer.readList(DebugInfoSection::readDirect);
this.player = null;
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeCollection(this.serverInfo, (buf, section) -> section.write(player, buf));
}
@Override
public boolean handle(NetworkEvent.Context context) {
context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::handleOnClient));
return true;
}
private void printInfo(String side, Player player, List<DebugInfoSection> sections, StringBuilder output) {
output.append("<details>");
output.append('\n');
output.append("<summary>")
.append(side)
.append(" Info")
.append("</summary>");
output.append('\n')
.append('\n');
output.append("```");
output.append('\n');
for (int i = 0; i < sections.size(); i++) {
if (i != 0) {
output.append('\n');
}
sections.get(i)
.print(player, line -> output.append(line)
.append('\n'));
}
output.append("```");
output.append('\n')
.append('\n');
output.append("</details>");
output.append('\n');
}
@OnlyIn(Dist.CLIENT)
private void handleOnClient() {
Player player = Objects.requireNonNull(Minecraft.getInstance().player);
StringBuilder output = new StringBuilder();
List<DebugInfoSection> clientInfo = DebugInformation.getClientInfo();
printInfo("Client", player, clientInfo, output);
output.append("\n\n");
printInfo("Server", player, serverInfo, output);
String text = output.toString();
Minecraft.getInstance().keyboardHandler.setClipboard(text);
Lang.translate("command.debuginfo.saved_to_clipboard")
.color(DyeHelper.DYE_TABLE.get(DyeColor.LIME)
.getFirst())
.sendChat(player);
}
}

View File

@ -0,0 +1,112 @@
package com.simibubi.create.infrastructure.debugInfo.element;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.infrastructure.debugInfo.DebugInformation;
import com.simibubi.create.infrastructure.debugInfo.InfoProvider;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
/**
* A section for organizing debug information. Can contain both information and other sections.
* To create one, use the {@link #builder(String) builder} method.
*/
public record DebugInfoSection(String name, ImmutableList<InfoElement> elements) implements InfoElement {
@Override
public void write(Player player, FriendlyByteBuf buffer) {
buffer.writeBoolean(true);
buffer.writeUtf(name);
buffer.writeCollection(elements, (buf, element) -> element.write(player, buf));
}
public Builder builder() {
return builder(name).putAll(elements);
}
@Override
public void print(int depth, @Nullable Player player, Consumer<String> lineConsumer) {
String indent = DebugInformation.getIndent(depth);
lineConsumer.accept(indent + name + ":");
elements.forEach(element -> element.print(depth + 1, player, lineConsumer));
}
public static DebugInfoSection read(FriendlyByteBuf buffer) {
String name = buffer.readUtf();
ArrayList<InfoElement> elements = buffer.readCollection(ArrayList::new, InfoElement::read);
return new DebugInfoSection(name, ImmutableList.copyOf(elements));
}
public static DebugInfoSection readDirect(FriendlyByteBuf buf) {
buf.readBoolean(); // discard type marker
return read(buf);
}
public static Builder builder(String name) {
return new Builder(null, name);
}
public static DebugInfoSection of(String name, Collection<DebugInfoSection> children) {
return builder(name).putAll(children).build();
}
public static class Builder {
private final Builder parent;
private final String name;
private final ImmutableList.Builder<InfoElement> elements;
public Builder(Builder parent, String name) {
this.parent = parent;
this.name = name;
this.elements = ImmutableList.builder();
}
public Builder put(InfoElement element) {
this.elements.add(element);
return this;
}
public Builder put(String key, InfoProvider provider) {
return put(new InfoEntry(key, provider));
}
public Builder put(String key, Supplier<String> value) {
return put(key, player -> value.get());
}
public Builder put(String key, String value) {
return put(key, player -> value);
}
public Builder putAll(Collection<? extends InfoElement> elements) {
elements.forEach(this::put);
return this;
}
public Builder section(String name) {
return new Builder(this, name);
}
public Builder finishSection() {
if (parent == null) {
throw new IllegalStateException("Cannot finish the root section");
}
parent.elements.add(this.build());
return parent;
}
public DebugInfoSection build() {
return new DebugInfoSection(name, elements.build());
}
public void buildTo(Consumer<DebugInfoSection> consumer) {
consumer.accept(this.build());
}
}
}

View File

@ -0,0 +1,27 @@
package com.simibubi.create.infrastructure.debugInfo.element;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
public sealed interface InfoElement permits DebugInfoSection, InfoEntry {
void write(Player player, FriendlyByteBuf buffer);
void print(int depth, @Nullable Player player, Consumer<String> lineConsumer);
default void print(@Nullable Player player, Consumer<String> lineConsumer) {
print(0, player, lineConsumer);
}
static InfoElement read(FriendlyByteBuf buffer) {
boolean section = buffer.readBoolean();
if (section) {
return DebugInfoSection.read(buffer);
} else {
return InfoEntry.read(buffer);
}
}
}

View File

@ -0,0 +1,52 @@
package com.simibubi.create.infrastructure.debugInfo.element;
import com.simibubi.create.infrastructure.debugInfo.DebugInformation;
import com.simibubi.create.infrastructure.debugInfo.InfoProvider;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public record InfoEntry(String name, InfoProvider provider) implements InfoElement {
public InfoEntry(String name, String info) {
this(name, player -> info);
}
@Override
public void write(Player player, FriendlyByteBuf buffer) {
buffer.writeBoolean(false);
buffer.writeUtf(name);
buffer.writeUtf(provider.getInfoSafe(player));
}
@Override
public void print(int depth, @Nullable Player player, Consumer<String> lineConsumer) {
String value = provider.getInfoSafe(player);
String indent = DebugInformation.getIndent(depth);
if (value.contains("\n")) {
String[] lines = value.split("\n");
String firstLine = lines[0];
String lineStart = name + ": ";
lineConsumer.accept(indent + lineStart + firstLine);
String extraIndent = Stream.generate(() -> " ").limit(lineStart.length()).collect(Collectors.joining());
for (int i = 1; i < lines.length; i++) {
lineConsumer.accept(indent + extraIndent + lines[i]);
}
} else {
lineConsumer.accept(indent + name + ": " + value);
}
}
public static InfoEntry read(FriendlyByteBuf buffer) {
String name = buffer.readUtf();
String value = buffer.readUtf();
return new InfoEntry(name, value);
}
}

View File

@ -1001,6 +1001,9 @@
"create.gui.config.overlay7": "Run /create overlay reset",
"create.gui.config.overlay8": "to reset to the default position",
"create.command.debuginfo.sending": "Collecting debug information...",
"create.command.debuginfo.saved_to_clipboard": "Debug information has been copied to your clipboard.",
"create.command.killTPSCommand": "killtps",
"create.command.killTPSCommand.status.slowed_by.0": "[Create]: Server tick is currently slowed by %s ms :o",
"create.command.killTPSCommand.status.slowed_by.1": "[Create]: Server tick is slowed by %s ms now >:)",
@ -1013,12 +1016,12 @@
"create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world",
"enchantment.create.capacity.desc": "Increases Backtank air capacity.",
"enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.",
"enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.",
"create.bogey.style.updated_style": "Updated style",
"create.bogey.style.updated_style_and_size": "Updated style and size",
"create.bogey.style.no_other_sizes": "No other sizes",
"create.bogey.style.invalid": "Unnamed style",
"create.bogey.style.standard": "Standard"
"create.bogey.style.updated_style": "Updated style",
"create.bogey.style.updated_style_and_size": "Updated style and size",
"create.bogey.style.no_other_sizes": "No other sizes",
"create.bogey.style.invalid": "Unnamed style",
"create.bogey.style.standard": "Standard"
}

View File

@ -22,9 +22,14 @@
"accessor.GameTestHelperAccessor",
"accessor.LivingEntityAccessor",
"accessor.NbtAccounterAccessor",
"accessor.ServerLevelAccessor"
"accessor.ServerLevelAccessor",
"accessor.SystemReportAccessor"
],
"client": [
"accessor.AgeableListModelAccessor",
"accessor.GameRendererAccessor",
"accessor.HumanoidArmorLayerAccessor",
"accessor.ParticleEngineAccessor",
"client.BlockDestructionProgressMixin",
"client.CameraMixin",
"client.EntityContraptionInteractionMixin",
@ -35,11 +40,7 @@
"client.MapRendererMapInstanceMixin",
"client.ModelDataRefreshMixin",
"client.PlayerRendererMixin",
"client.WindowResizeMixin",
"accessor.AgeableListModelAccessor",
"accessor.GameRendererAccessor",
"accessor.HumanoidArmorLayerAccessor",
"accessor.ParticleEngineAccessor"
"client.WindowResizeMixin"
],
"injectors": {
"defaultRequire": 1