Code cleanup and refactoring before porting
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
package com.hypherionmc.craterlib;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class CraterConstants {
|
||||
public static final String MOD_ID = "craterlib";
|
||||
public static final String MOD_NAME = "CraterLib";
|
||||
public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME);
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package com.hypherionmc.craterlib.api.blockentity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper Interface for BlockEntities that tick both Client and Server Side
|
||||
*/
|
||||
public interface ISidedTickable {
|
||||
|
||||
void serverTick(Level level, BlockPos pos, BlockState state, BlockEntity blockEntity);
|
||||
void clientTick(Level level, BlockPos pos, BlockState state, BlockEntity blockEntity);
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.hypherionmc.craterlib.api.blockentity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper Interface for BlockEntities that only tick on a single side
|
||||
*/
|
||||
public interface ITickable {
|
||||
|
||||
void tick(Level level, BlockPos pos, BlockState state, BlockEntity blockEntity);
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.hypherionmc.craterlib.api.blockentity.caps;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Wrapper class for Forge capabilities to remove duplicate code from modules
|
||||
*/
|
||||
public enum CraterCapabilityHandler {
|
||||
ENERGY,
|
||||
ITEM,
|
||||
FLUID
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.hypherionmc.craterlib.api.blockentity.caps;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Interface for BlockEntities to expose "capabilities" across fabric/forge
|
||||
*/
|
||||
public interface ICraterCapProvider {
|
||||
|
||||
<T> Optional<T> getCapability(CraterCapabilityHandler handler, @Nullable Direction side);
|
||||
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
package com.hypherionmc.craterlib.api.creativetab;
|
||||
|
||||
import com.hypherionmc.craterlib.core.systems.internal.CreativeTabRegistry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.CreativeModeTabs;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CraterCreativeModeTab implements Supplier<CreativeModeTab> {
|
||||
|
||||
private final ResourceLocation resourceLocation;
|
||||
private final Supplier<ItemStack> icon;
|
||||
private final String backgroundSuffix;
|
||||
private CreativeModeTab tab;
|
||||
|
||||
protected CraterCreativeModeTab(Builder builder) {
|
||||
this.resourceLocation = builder.location;
|
||||
this.icon = builder.stack;
|
||||
this.backgroundSuffix = builder.backgroundSuffix == null ? "" : builder.backgroundSuffix;
|
||||
|
||||
CreativeTabRegistry.registerTab(this);
|
||||
}
|
||||
|
||||
public ResourceLocation getResourceLocation() {
|
||||
return resourceLocation;
|
||||
}
|
||||
|
||||
public Supplier<ItemStack> getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getBackgroundSuffix() {
|
||||
return backgroundSuffix;
|
||||
}
|
||||
|
||||
public void setTab(CreativeModeTab tab) {
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final ResourceLocation location;
|
||||
private Supplier<ItemStack> stack;
|
||||
private String backgroundSuffix;
|
||||
|
||||
public Builder(ResourceLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public CraterCreativeModeTab.Builder setIcon(Supplier<ItemStack> icon) {
|
||||
stack = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCreativeModeTab.Builder backgroundSuffix(String backgroundSuffix) {
|
||||
this.backgroundSuffix = backgroundSuffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCreativeModeTab build() {
|
||||
return new CraterCreativeModeTab(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreativeModeTab get() {
|
||||
return tab == null ? CreativeModeTabs.getDefaultTab() : tab;
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package com.hypherionmc.craterlib.api.event.client;
|
||||
|
||||
import com.hypherionmc.craterlib.core.event.CraterEvent;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.color.item.ItemColors;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A wrapped event to allow Block and Item Color Registration
|
||||
*/
|
||||
public class ColorRegistrationEvent {
|
||||
|
||||
public static class Blocks extends CraterEvent {
|
||||
|
||||
private final BlockColors colors;
|
||||
|
||||
public Blocks(BlockColors colors) {
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public BlockColors getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCancel() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Items extends CraterEvent {
|
||||
|
||||
private final ItemColors colors;
|
||||
|
||||
public Items(ItemColors colors) {
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public ItemColors getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCancel() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.hypherionmc.craterlib.api.rendering;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper Interface for defining Block render types
|
||||
*/
|
||||
public interface CustomRenderType {
|
||||
|
||||
/**
|
||||
* Get the render type of the block
|
||||
*/
|
||||
RenderType getCustomRenderType();
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.hypherionmc.craterlib.api.rendering;
|
||||
|
||||
import net.minecraft.client.color.block.BlockColor;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper Interface for Dyable Blocks
|
||||
*/
|
||||
public interface DyableBlock {
|
||||
|
||||
/**
|
||||
* Get the BlockColor handler for the block
|
||||
*/
|
||||
BlockColor dyeHandler();
|
||||
|
||||
/**
|
||||
* Get the default Dye Color for Un-dyed states
|
||||
*/
|
||||
DyeColor defaultDyeColor();
|
||||
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package com.hypherionmc.craterlib.api.rendering;
|
||||
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper Interface for Dyable Items
|
||||
*/
|
||||
public interface ItemDyable {
|
||||
|
||||
/**
|
||||
* Get the DyeColor of the Item
|
||||
*/
|
||||
public DyeColor getColor(ItemStack stack);
|
||||
|
||||
}
|
@@ -0,0 +1,388 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config;
|
||||
|
||||
import com.hypherionmc.craterlib.CraterConstants;
|
||||
import com.hypherionmc.craterlib.client.gui.config.widgets.*;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.SubConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.Tooltip;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.*;
|
||||
import me.hypherionmc.moonconfig.core.conversion.SpecComment;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.gui.GuiComponent;
|
||||
import net.minecraft.client.gui.screens.ConfirmScreen;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public class CraterConfigScreen extends Screen {
|
||||
public static final float SCROLLBAR_BOTTOM_COLOR = .5f;
|
||||
public static final float SCROLLBAR_TOP_COLOR = .67f;
|
||||
private static final int TOP = 26;
|
||||
private static final int BOTTOM = 24;
|
||||
private final Screen parent;
|
||||
private final List<Option<?>> options = new ArrayList<>();
|
||||
private final ModuleConfig config;
|
||||
public double scrollerAmount;
|
||||
private boolean dragging;
|
||||
|
||||
public CraterConfigScreen(ModuleConfig config, Screen parent, Object subConfig) {
|
||||
super(Component.translatable("cl." + config.getClass().getSimpleName().toLowerCase() + ".title"));
|
||||
this.parent = parent;
|
||||
this.config = config;
|
||||
if (subConfig != null) {
|
||||
setupScreenFromConfig(subConfig, subConfig.getClass());
|
||||
} else {
|
||||
setupScreenFromConfig(config, config.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public CraterConfigScreen(ModuleConfig config, Screen parent) {
|
||||
this(config, parent, null);
|
||||
}
|
||||
|
||||
private static Component toText(Enum<?> val) {
|
||||
return Component.translatable(val.toString());
|
||||
}
|
||||
|
||||
private static Component toText(Boolean bool) {
|
||||
return Component.translatable(bool.toString());
|
||||
}
|
||||
|
||||
private void setupScreenFromConfig(Object object, Class<?> clazz) {
|
||||
while (clazz != Object.class) {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
final int fieldModifiers = field.getModifiers();
|
||||
if (object == null || Modifier.isStatic(fieldModifiers) || Modifier.isTransient(fieldModifiers)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
Object val = field.get(object);
|
||||
|
||||
/* Lang Stuff */
|
||||
String baseLangKey = "cl." + clazz.getSimpleName().toLowerCase() + "." + field.getName().toLowerCase();
|
||||
String[] tooltipLang = field.isAnnotationPresent(SpecComment.class) ? new String[]{field.getAnnotation(SpecComment.class).value()} : new String[0];
|
||||
if (field.isAnnotationPresent(Tooltip.class)) {
|
||||
tooltipLang = field.getAnnotation(Tooltip.class).value();
|
||||
}
|
||||
|
||||
add(Component.translatable(baseLangKey),
|
||||
val,
|
||||
() -> val,
|
||||
(ret) -> {
|
||||
try {
|
||||
field.set(object, ret);
|
||||
config.saveConfig(config);
|
||||
} catch (IllegalAccessException e) {
|
||||
CraterConstants.LOG.error("Failed to update value for field {} in config {}", field.getName(), config.getConfigName(), e);
|
||||
}
|
||||
},
|
||||
field.isAnnotationPresent(SubConfig.class),
|
||||
tooltipLang
|
||||
);
|
||||
} catch (IllegalAccessException e) {
|
||||
CraterConstants.LOG.error("Failed to access value for field {} in config {}", field.getName(), config.getConfigName(), e);
|
||||
}
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void add(Component text, T value, @Nullable Supplier<T> defaultValue, Consumer<T> savingConsumer, boolean isSubConfig, String... langKeys) {
|
||||
Option<T> option = (Option<T>) createOption(value, isSubConfig);
|
||||
option.text = text;
|
||||
option.defaultValue = defaultValue;
|
||||
option.savingConsumer = savingConsumer;
|
||||
option.originalValue = value;
|
||||
option.value = value;
|
||||
option.setLangKeys(List.of(langKeys));
|
||||
options.add(option);
|
||||
option.onAdd();
|
||||
}
|
||||
|
||||
private <T> Option<?> createOption(T value, boolean isSubConfig) {
|
||||
if (value instanceof Enum) {
|
||||
Object[] objects = value.getClass().getEnumConstants();
|
||||
return new ToggleButton<Enum<?>>((List) Arrays.asList(objects), CraterConfigScreen::toText);
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return new ToggleButton<>(Arrays.asList(Boolean.TRUE, Boolean.FALSE), CraterConfigScreen::toText);
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return new TextConfigOption<>(Function.identity(), Function.identity());
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return new TextConfigOption<>(Objects::toString, Integer::valueOf);
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return new TextConfigOption<>(Objects::toString, Long::valueOf);
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return new TextConfigOption<>(Objects::toString, Double::valueOf);
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
return new TextConfigOption<>(Objects::toString, Float::valueOf);
|
||||
}
|
||||
if (value instanceof BigInteger) {
|
||||
return new TextConfigOption<>(Objects::toString, BigInteger::new);
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return new TextConfigOption<>(Objects::toString, BigDecimal::new);
|
||||
}
|
||||
if (value instanceof ResourceLocation) {
|
||||
return new TextConfigOption<>(Objects::toString, ResourceLocation::new);
|
||||
}
|
||||
if (isSubConfig) {
|
||||
return new SubConfigWidget<>(config, this, value);
|
||||
}
|
||||
throw new IllegalArgumentException(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
((List) children()).addAll(options);
|
||||
|
||||
int buttonWidths = Math.min(200, (width - 50 - 12) / 3);
|
||||
addRenderableWidget(new InternalConfigButton(this, width / 2 - buttonWidths - 3, height - 22, buttonWidths, 20, Component.empty(), true));
|
||||
addRenderableWidget(new InternalConfigButton(this, width / 2 + 3, height - 22, buttonWidths, 20, Component.empty(), false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
overlayBackground(matrices, TOP, height - BOTTOM, 32);
|
||||
|
||||
renderScrollBar();
|
||||
|
||||
matrices.pushPose();
|
||||
matrices.translate(0, 0, 500.0);
|
||||
overlayBackground(matrices, 0, TOP, 64);
|
||||
overlayBackground(matrices, height - BOTTOM, height, 64);
|
||||
renderShadow(matrices);
|
||||
drawCenteredString(matrices, font, getTitle(), width / 2, 9, 0xFFFFFF);
|
||||
super.render(matrices, mouseX, mouseY, delta);
|
||||
matrices.popPose();
|
||||
|
||||
int y = (int) (TOP + 4 - Math.round(scrollerAmount));
|
||||
for (Option<?> option : options) {
|
||||
int height1 = option.height();
|
||||
option.render(minecraft, font, 40, y, width - 80, height1, matrices, mouseX, mouseY, delta);
|
||||
renderConfigTooltip(matrices, mouseX, mouseY, 40, y, font.width(option.text), height1, option.text.getString(), option.getLangKeys().toArray(new String[0]));
|
||||
y += height1;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderScrollBar() {
|
||||
int listHeight = height - BOTTOM - TOP;
|
||||
int totalHeight = totalHeight();
|
||||
if (totalHeight > listHeight) {
|
||||
int maxScroll = Math.max(0, totalHeight - listHeight);
|
||||
int height = listHeight * listHeight / totalHeight;
|
||||
height = Mth.clamp(height, 32, listHeight);
|
||||
height = Math.max(10, height);
|
||||
int minY = Math.min(Math.max((int) scrollerAmount * (listHeight - height) / maxScroll + TOP, TOP), this.height - BOTTOM - height);
|
||||
|
||||
int scrollbarPositionMaxX = width;
|
||||
int scrollbarPositionMinX = scrollbarPositionMaxX - 6;
|
||||
|
||||
int maxY = this.height - BOTTOM;
|
||||
//RenderSystem.disableTexture();
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder buffer = tesselator.getBuilder();
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||
|
||||
buffer.vertex(scrollbarPositionMinX, maxY, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
buffer.vertex(scrollbarPositionMaxX, maxY, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
buffer.vertex(scrollbarPositionMaxX, TOP, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
buffer.vertex(scrollbarPositionMinX, TOP, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
|
||||
buffer.vertex(scrollbarPositionMinX, minY + height, 0.0D).color(SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, 1).endVertex();
|
||||
buffer.vertex(scrollbarPositionMaxX, minY + height, 0.0D).color(SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, 1).endVertex();
|
||||
buffer.vertex(scrollbarPositionMaxX, minY, 0.0D).color(SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, 1).endVertex();
|
||||
buffer.vertex(scrollbarPositionMinX, minY, 0.0D).color(SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, SCROLLBAR_BOTTOM_COLOR, 1).endVertex();
|
||||
buffer.vertex(scrollbarPositionMinX, (minY + height - 1), 0.0D).color(SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, 1).endVertex();
|
||||
buffer.vertex((scrollbarPositionMaxX - 1), (minY + height - 1), 0.0D).color(SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, 1).endVertex();
|
||||
buffer.vertex((scrollbarPositionMaxX - 1), minY, 0.0D).color(SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, 1).endVertex();
|
||||
buffer.vertex(scrollbarPositionMinX, minY, 0.0D).color(SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, SCROLLBAR_TOP_COLOR, 1).endVertex();
|
||||
tesselator.end();
|
||||
RenderSystem.disableBlend();
|
||||
//RenderSystem.enableTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private void renderShadow(PoseStack matrices) {
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder buffer = tesselator.getBuilder();
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.blendFuncSeparate(770, 771, 0, 1);
|
||||
//RenderSystem.disableTexture();
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
|
||||
Matrix4f matrix = matrices.last().pose();
|
||||
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
|
||||
buffer.vertex(matrix, 0, TOP + 4, 0.0F).uv(0, 1).color(0, 0, 0, 0).endVertex();
|
||||
buffer.vertex(matrix, width, TOP + 4, 0.0F).uv(1, 1).color(0, 0, 0, 0).endVertex();
|
||||
buffer.vertex(matrix, width, TOP, 0.0F).uv(1, 0).color(0, 0, 0, 185).endVertex();
|
||||
buffer.vertex(matrix, 0, TOP, 0.0F).uv(0, 0).color(0, 0, 0, 185).endVertex();
|
||||
buffer.vertex(matrix, 0, height - BOTTOM, 0.0F).uv(0, 1).color(0, 0, 0, 185).endVertex();
|
||||
buffer.vertex(matrix, width, height - BOTTOM, 0.0F).uv(1, 1).color(0, 0, 0, 185).endVertex();
|
||||
buffer.vertex(matrix, width, height - BOTTOM - 4, 0.0F).uv(1, 0).color(0, 0, 0, 0).endVertex();
|
||||
buffer.vertex(matrix, 0, height - BOTTOM - 4, 0.0F).uv(0, 0).color(0, 0, 0, 0).endVertex();
|
||||
tesselator.end();
|
||||
//RenderSystem.enableTexture();
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
|
||||
protected void overlayBackground(PoseStack matrices, int h1, int h2, int color) {
|
||||
overlayBackground(matrices.last().pose(), 0, h1, width, h2, color, color, color, 255, 255);
|
||||
}
|
||||
|
||||
protected void overlayBackground(Matrix4f matrix, int minX, int minY, int maxX, int maxY, int red, int green, int blue, int startAlpha, int endAlpha) {
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder buffer = tesselator.getBuilder();
|
||||
RenderSystem.setShaderTexture(0, GuiComponent.BACKGROUND_LOCATION);
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
|
||||
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
|
||||
buffer.vertex(matrix, minX, maxY, 0.0F).uv(minX / 32.0F, maxY / 32.0F).color(red, green, blue, endAlpha).endVertex();
|
||||
buffer.vertex(matrix, maxX, maxY, 0.0F).uv(maxX / 32.0F, maxY / 32.0F).color(red, green, blue, endAlpha).endVertex();
|
||||
buffer.vertex(matrix, maxX, minY, 0.0F).uv(maxX / 32.0F, minY / 32.0F).color(red, green, blue, startAlpha).endVertex();
|
||||
buffer.vertex(matrix, minX, minY, 0.0F).uv(minX / 32.0F, minY / 32.0F).color(red, green, blue, startAlpha).endVertex();
|
||||
tesselator.end();
|
||||
}
|
||||
|
||||
public int scrollHeight() {
|
||||
int totalHeight = totalHeight();
|
||||
int listHeight = height - BOTTOM - TOP;
|
||||
if (totalHeight <= listHeight) {
|
||||
return 0;
|
||||
}
|
||||
return totalHeight - listHeight;
|
||||
}
|
||||
|
||||
public int totalHeight() {
|
||||
int i = 8;
|
||||
for (Option<?> option : options) {
|
||||
i += option.height();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public boolean hasErrors() {
|
||||
for (Option<?> option : options) {
|
||||
if (option.hasErrors) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEdited() {
|
||||
for (Option<?> option : options) {
|
||||
if (option.isEdited()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void save() {
|
||||
for (Option option : options) {
|
||||
option.save();
|
||||
option.originalValue = option.value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
if (isEdited()) {
|
||||
minecraft.setScreen(new ConfirmScreen(this::acceptConfirm, Component.translatable("t.clc.quit_config"),
|
||||
Component.translatable("t.clc.quit_config_sure"),
|
||||
Component.translatable("t.clc.quit_discard"),
|
||||
Component.translatable("gui.cancel")));
|
||||
} else {
|
||||
minecraft.setScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(double d, double e, double f) {
|
||||
if (e >= TOP && e <= height - BOTTOM) {
|
||||
scrollerAmount = Mth.clamp(scrollerAmount - f * 16.0D, 0, scrollHeight());
|
||||
return true;
|
||||
}
|
||||
return super.mouseScrolled(d, e, f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double d, double e, int i) {
|
||||
this.dragging = i == 0 && d >= width - 6 && d < width;
|
||||
return super.mouseClicked(d, e, i) || dragging;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(double d, double e, int i, double f, double g) {
|
||||
if (super.mouseDragged(d, e, i, f, g)) {
|
||||
return true;
|
||||
}
|
||||
if (i != 0 || !this.dragging) {
|
||||
return false;
|
||||
}
|
||||
if (e < TOP) {
|
||||
scrollerAmount = 0;
|
||||
} else if (e > height - BOTTOM) {
|
||||
scrollerAmount = scrollHeight();
|
||||
} else {
|
||||
double h = Math.max(1, this.scrollHeight());
|
||||
int j = height - BOTTOM - TOP;
|
||||
int k = Mth.clamp((int) ((float) (j * j) / (float) this.scrollHeight()), 32, j - 8);
|
||||
double l = Math.max(1.0, h / (double) (j - k));
|
||||
scrollerAmount = Mth.clamp(scrollerAmount + g * l, 0, scrollHeight());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void acceptConfirm(boolean t) {
|
||||
if (!t) {
|
||||
minecraft.setScreen(this);
|
||||
} else {
|
||||
minecraft.setScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderConfigTooltip(PoseStack stack, int mouseX, int mouseY, int startX, int startY, int sizeX, int sizeY, String title, String... description) {
|
||||
if (mouseX > startX && mouseX < startX + sizeX) {
|
||||
if (mouseY > startY && mouseY < startY + sizeY) {
|
||||
List<Component> list = new ArrayList<>();
|
||||
list.add(Component.translatable(ChatFormatting.BOLD + "" + ChatFormatting.YELLOW + title));
|
||||
for (String desc : description) {
|
||||
list.add(Component.translatable(desc));
|
||||
}
|
||||
renderComponentTooltip(stack, list, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
|
||||
/** Copied from Cloth Config Lite
|
||||
* <a href="https://github.com/shedaniel/cloth-config-lite/blob/1.17/src/main/java/me/shedaniel/clothconfiglite/impl/option/AbstractWidgetOption.java">...</a>
|
||||
*/
|
||||
public class AbstractConfigWidget<T, W extends AbstractWidget> extends BaseWidget<T> {
|
||||
|
||||
public static final int buttonWidth = 200;
|
||||
public static final int buttonHeight = 20;
|
||||
public W widget;
|
||||
|
||||
@Override
|
||||
public void render(Minecraft minecraft, Font font, int x, int y, int width, int height, PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
super.render(minecraft, font, x, y, width, height, matrices, mouseX, mouseY, delta);
|
||||
int i = (widget instanceof EditBox ? 1 : 0);
|
||||
widget.setX(x + width - 200 - resetButtonOffset + i);
|
||||
widget.setY(y + i + 1);
|
||||
widget.render(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.TextColor;
|
||||
|
||||
/**
|
||||
* Copied from Cloth Config Lite
|
||||
* <a href="https://github.com/shedaniel/cloth-config-lite/blob/1.17/src/main/java/me/shedaniel/clothconfiglite/impl/option/BaseOption.java">...</a>
|
||||
*/
|
||||
public class BaseWidget<T> extends Option<T> {
|
||||
|
||||
public static final int resetButtonOffset = 48;
|
||||
private final Button resetButton = addChild(Button.builder(Component.literal("Reset"), this::onResetPressed).size(46, 20).build());
|
||||
private boolean hideReset = false;
|
||||
|
||||
private boolean isSubConfig = false;
|
||||
|
||||
private void onResetPressed(Button button) {
|
||||
value = defaultValue.get();
|
||||
reset();
|
||||
}
|
||||
|
||||
public void hideReset() {
|
||||
this.hideReset = true;
|
||||
}
|
||||
|
||||
public boolean isSubConfig() {
|
||||
return isSubConfig;
|
||||
}
|
||||
|
||||
public void setSubConfig(boolean subConfig) {
|
||||
isSubConfig = subConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Minecraft minecraft, Font font, int x, int y, int width, int height, PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
MutableComponent text = Component.literal(this.text.getString());
|
||||
boolean edited = isEdited() || hasErrors;
|
||||
if (edited) {
|
||||
text.withStyle(ChatFormatting.ITALIC);
|
||||
if (hasErrors) {
|
||||
text.withStyle(style -> style.withColor(TextColor.fromRgb(16733525)));
|
||||
}
|
||||
} else {
|
||||
text.withStyle(ChatFormatting.GRAY);
|
||||
}
|
||||
font.draw(matrices, text, x, y + 8, 0xFFFFFF);
|
||||
resetButton.setX(x + width - 46);
|
||||
resetButton.setY(y + 1);
|
||||
resetButton.active = isNotDefault();
|
||||
if (!hideReset) {
|
||||
resetButton.render(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.gui.components.AbstractButton;
|
||||
import net.minecraft.client.gui.narration.NarratedElementType;
|
||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public class InternalConfigButton extends AbstractButton {
|
||||
|
||||
CraterConfigScreen screen;
|
||||
boolean cancel;
|
||||
|
||||
public InternalConfigButton(CraterConfigScreen screen, int i, int j, int k, int l, Component component, boolean cancel) {
|
||||
super(i, j, k, l, component);
|
||||
this.screen = screen;
|
||||
this.cancel = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(@NotNull PoseStack poseStack, int i, int j, float f) {
|
||||
if (cancel) {
|
||||
setMessage(Component.translatable(screen.isEdited() ? "t.clc.cancel_discard" : "gui.cancel"));
|
||||
} else {
|
||||
boolean hasErrors = screen.hasErrors();
|
||||
active = screen.isEdited() && !hasErrors;
|
||||
setMessage(Component.translatable(hasErrors ? "t.clc.error" : "t.clc.save"));
|
||||
}
|
||||
super.render(poseStack, i, j, f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {
|
||||
narrationElementOutput.add(NarratedElementType.USAGE, getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPress() {
|
||||
if (cancel) {
|
||||
screen.onClose();
|
||||
} else {
|
||||
screen.save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.events.AbstractContainerEventHandler;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Copied from Cloth Config Lite
|
||||
* <a href="https://github.com/shedaniel/cloth-config-lite/blob/1.17/src/main/java/me/shedaniel/clothconfiglite/impl/option/Option.java">...</a>
|
||||
*/
|
||||
public abstract class Option<T> extends AbstractContainerEventHandler {
|
||||
|
||||
public Component text;
|
||||
@Nullable
|
||||
public Supplier<T> defaultValue;
|
||||
public Consumer<T> savingConsumer;
|
||||
public T originalValue;
|
||||
public T value;
|
||||
public boolean hasErrors;
|
||||
public List<? extends GuiEventListener> children = new ArrayList<>();
|
||||
private List<String> langKeys = new ArrayList<>();
|
||||
|
||||
public List<String> getLangKeys() {
|
||||
return langKeys;
|
||||
}
|
||||
|
||||
public void setLangKeys(List<String> langKeys) {
|
||||
this.langKeys = langKeys;
|
||||
}
|
||||
|
||||
public abstract void render(Minecraft minecraft, Font font, int x, int y, int width, int height, PoseStack matrices, int mouseX, int mouseY, float delta);
|
||||
|
||||
public int height() {
|
||||
return 22;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends GuiEventListener> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
protected <R extends GuiEventListener> R addChild(R listener) {
|
||||
((List) children).add(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
public void onAdd() {}
|
||||
|
||||
protected void reset() {
|
||||
onAdd();
|
||||
}
|
||||
|
||||
public boolean isEdited() {
|
||||
return !Objects.equals(originalValue, value);
|
||||
}
|
||||
|
||||
protected boolean isNotDefault() {
|
||||
return defaultValue != null && !Objects.equals(defaultValue.get(), value);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
savingConsumer.accept(value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public class SubConfigWidget<T> extends AbstractConfigWidget<T, Button> {
|
||||
|
||||
private final Object subConfig;
|
||||
private final ModuleConfig config;
|
||||
private final Screen screen;
|
||||
|
||||
public SubConfigWidget(ModuleConfig config, Screen screen, Object subConfig) {
|
||||
this.config = config;
|
||||
this.subConfig = subConfig;
|
||||
this.screen = screen;
|
||||
|
||||
this.widget = addChild(Button.builder(Component.translatable("t.clc.opensubconfig"), this::openSubConfig).size(200, buttonHeight).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Minecraft minecraft, Font font, int x, int y, int width, int height, PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
this.text = Component.literal(subConfig.getClass().getSimpleName().toLowerCase());
|
||||
this.hideReset();
|
||||
super.render(minecraft, font, x, y, width, height, matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
private void openSubConfig(Button button) {
|
||||
Minecraft.getInstance().setScreen(new CraterConfigScreen(config, screen, subConfig));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Copied from Cloth Config Lite
|
||||
* <a href="https://github.com/shedaniel/cloth-config-lite/blob/1.17/src/main/java/me/shedaniel/clothconfiglite/impl/option/TextFieldOption.java">...</a>
|
||||
*/
|
||||
public class TextConfigOption <T> extends AbstractConfigWidget<T, WrappedEditBox> {
|
||||
|
||||
private final Function<T, String> toString;
|
||||
private final Function<String, T> fromString;
|
||||
|
||||
public TextConfigOption(Function<T, String> toString, Function<String, T> fromString) {
|
||||
this.toString = toString;
|
||||
this.fromString = fromString;
|
||||
this.widget = addChild(new WrappedEditBox(Minecraft.getInstance().font, 0, 0, 198, 18, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdd() {
|
||||
widget.setMaxLength(1000000);
|
||||
widget.setValue(toString.apply(value));
|
||||
widget.setResponder(this::update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Minecraft minecraft, Font font, int x, int y, int width, int height, PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
widget.setTextColor(hasErrors ? 16733525 : 14737632);
|
||||
super.render(minecraft, font, x, y, width, height, matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
private void update(String s) {
|
||||
try {
|
||||
this.value = fromString.apply(s);
|
||||
this.hasErrors = false;
|
||||
} catch (Exception e) {
|
||||
this.hasErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Copied from Cloth Config Lite
|
||||
* <a href="https://github.com/shedaniel/cloth-config-lite/blob/1.17/src/main/java/me/shedaniel/clothconfiglite/impl/option/ToggleOption.java">...</a>
|
||||
*/
|
||||
public class ToggleButton <T> extends AbstractConfigWidget<T, Button> {
|
||||
|
||||
private final List<T> options;
|
||||
private final Function<T, Component> toComponent;
|
||||
|
||||
public ToggleButton(List<T> options, Function<T, Component> toComponent) {
|
||||
this.options = options;
|
||||
this.toComponent = toComponent;
|
||||
this.widget = addChild(Button.builder(Component.empty(), this::switchNext).size(buttonWidth, buttonHeight).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdd() {
|
||||
widget.setMessage(toComponent.apply(value));
|
||||
}
|
||||
|
||||
private void switchNext(Button button) {
|
||||
value = options.get((options.indexOf(value) + 1) % options.size());
|
||||
onAdd();
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public class WrappedEditBox extends EditBox {
|
||||
|
||||
public WrappedEditBox(Font font, int i, int j, int k, int l, @NotNull Component component) {
|
||||
super(font, i, j, k, l, component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocused(boolean bl) {
|
||||
for (GuiEventListener child : Minecraft.getInstance().screen.children()) {
|
||||
if (child instanceof TextConfigOption<?> option) {
|
||||
WrappedEditBox box = option.widget;
|
||||
box.setFocused(box == this);
|
||||
}
|
||||
}
|
||||
super.setFocused(bl);
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package com.hypherionmc.craterlib.client.gui.widgets;
|
||||
|
||||
import net.minecraft.client.gui.components.AbstractSliderButton;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A custom slider widget used for Time. Mostly used by the Hyper Lighting Smoke Machine
|
||||
*/
|
||||
public class TimeSliderWidget extends AbstractSliderButton {
|
||||
|
||||
private final double maxValue;
|
||||
private final ISliderChanged sliderChanged;
|
||||
|
||||
public TimeSliderWidget(int x, int y, int width, int height, Component text, double value, double maxValue, ISliderChanged sliderChanged) {
|
||||
super(x, y, width, height, text, value / maxValue);
|
||||
this.maxValue = maxValue;
|
||||
this.sliderChanged = sliderChanged;
|
||||
this.updateMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateMessage() {
|
||||
this.setMessage(getDisplayString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyValue() {
|
||||
this.sliderChanged.onSliderChange(this);
|
||||
}
|
||||
|
||||
private Component getDisplayString() {
|
||||
long seconds = Math.round(this.value * this.maxValue / 20);
|
||||
long minutes = Math.round(seconds / 60);
|
||||
if (this.value * this.maxValue >= 1200) {
|
||||
String appendString = (minutes == 1) ? "Minute" : "Minutes";
|
||||
String doSeconds = ((seconds - (minutes * 60)) > 0) ? ", " + (seconds - (minutes * 60)) + " Seconds" : "";
|
||||
return Component.literal(minutes + " " + appendString + doSeconds);
|
||||
} else {
|
||||
return Component.literal(seconds + " Seconds");
|
||||
}
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public interface ISliderChanged {
|
||||
void onSliderChange(TimeSliderWidget slider);
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.hypherionmc.craterlib.client.registry;
|
||||
|
||||
import com.hypherionmc.craterlib.api.rendering.DyableBlock;
|
||||
import com.hypherionmc.craterlib.api.rendering.ItemDyable;
|
||||
import com.hypherionmc.craterlib.client.rendering.ItemColorHandler;
|
||||
import com.hypherionmc.craterlib.core.platform.ClientPlatform;
|
||||
import me.hypherionmc.craterlib.systems.reg.RegistrationProvider;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.color.item.ItemColors;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper for registering Block and Item color handlers
|
||||
*/
|
||||
public class ClientRegistry {
|
||||
|
||||
/**
|
||||
* Register Block Color Handlers
|
||||
*
|
||||
* @param colors Existing block colors obtained from {@link com.hypherionmc.craterlib.api.event.client.ColorRegistrationEvent}
|
||||
* @param blocks The blocks registered for the module
|
||||
*/
|
||||
public static void registerBlockColors(@NotNull BlockColors colors, @NotNull RegistrationProvider<Block> blocks) {
|
||||
blocks.getEntries().forEach(blockRegistryObject -> {
|
||||
if (blockRegistryObject.get() instanceof DyableBlock dyableBlock) {
|
||||
colors.register(dyableBlock.dyeHandler(), (Block) dyableBlock);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Item Color Handlers
|
||||
*
|
||||
* @param colors Existing item colors obtained from {@link com.hypherionmc.craterlib.api.event.client.ColorRegistrationEvent}
|
||||
* @param items The items registered for the module
|
||||
*/
|
||||
public static void registerItemColors(@NotNull ItemColors colors, @NotNull RegistrationProvider<Item> items) {
|
||||
items.getEntries().forEach(itemRegistryObject -> {
|
||||
if (itemRegistryObject.get() instanceof ItemDyable itemDyable) {
|
||||
colors.register(new ItemColorHandler(), (Item) itemDyable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link net.minecraft.client.renderer.blockentity.BlockEntityRenderer} for a BlockEntity
|
||||
* @param blockEntityType The BlockEntity the renderer belongs to
|
||||
* @param blockEntityRendererFactory The renderer factory
|
||||
*/
|
||||
public static void registerBlockEntityRenderer(@NotNull BlockEntityType<? extends BlockEntity> blockEntityType, @NotNull BlockEntityRendererProvider blockEntityRendererFactory) {
|
||||
ClientPlatform.CLIENT_HELPER.registerBlockEntityRenderer(blockEntityType, blockEntityRendererFactory);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package com.hypherionmc.craterlib.client.rendering;
|
||||
|
||||
import com.hypherionmc.craterlib.api.rendering.ItemDyable;
|
||||
import com.hypherionmc.craterlib.util.RenderUtils;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper Class for Dyable Items implementing a simple color handler
|
||||
*/
|
||||
public class ItemColorHandler implements ItemColor {
|
||||
|
||||
/***
|
||||
* Get the color for the Item/ItemStack
|
||||
* @param stack The ItemStack to read the color from
|
||||
* @param tintIndex No Comment
|
||||
* @return Integer value of the color
|
||||
*/
|
||||
@Override
|
||||
public int getColor(@NotNull ItemStack stack, int tintIndex) {
|
||||
return this.getColorFromStack(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the color for the specific items stack, or return BLACK (0)
|
||||
*
|
||||
* @param stack The ItemStack to read the color from
|
||||
* @return Integer value of the color
|
||||
*/
|
||||
private int getColorFromStack(@NotNull ItemStack stack) {
|
||||
if (stack.getItem() instanceof ItemDyable itemDyable) {
|
||||
return RenderUtils.renderColorFromDye(itemDyable.getColor(stack));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package com.hypherionmc.craterlib.common.blockentity;
|
||||
|
||||
import com.hypherionmc.craterlib.api.blockentity.caps.CraterCapabilityHandler;
|
||||
import com.hypherionmc.craterlib.api.blockentity.caps.ICraterCapProvider;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A Wrapped Block Entity to incorporate CraterLib's universal capability provider
|
||||
*/
|
||||
public class CraterBlockEntity extends BlockEntity implements ICraterCapProvider {
|
||||
|
||||
public CraterBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state) {
|
||||
super(blockEntityType, pos, state);
|
||||
}
|
||||
|
||||
public void sendUpdates() {
|
||||
level.blockEntityChanged(this.getBlockPos());
|
||||
level.sendBlockUpdated(this.getBlockPos(), level.getBlockState(this.getBlockPos()), level.getBlockState(this.getBlockPos()), 3);
|
||||
setChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientboundBlockEntityDataPacket getUpdatePacket() {
|
||||
return ClientboundBlockEntityDataPacket.create(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getUpdateTag() {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
saveAdditional(compoundTag);
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getCapability(CraterCapabilityHandler handler, @Nullable Direction side) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package com.hypherionmc.craterlib.common.blockentity;
|
||||
|
||||
import com.hypherionmc.craterlib.api.blockentity.caps.CraterCapabilityHandler;
|
||||
import com.hypherionmc.craterlib.core.platform.Platform;
|
||||
import com.hypherionmc.craterlib.core.systems.fluid.CraterFluidTank;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A wrapped BlockEntity containing a fluid tank
|
||||
*/
|
||||
public class FluidContainerBlockEntity extends CraterBlockEntity {
|
||||
|
||||
public final CraterFluidTank fluidTank;
|
||||
|
||||
public FluidContainerBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state, int capacity) {
|
||||
super(blockEntityType, pos, state);
|
||||
fluidTank = Platform.FLUID_HELPER.createFluidTank(capacity);
|
||||
}
|
||||
|
||||
public FluidContainerBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state, int capacity, Fluid... validFluids) {
|
||||
super(blockEntityType, pos, state);
|
||||
fluidTank = Platform.FLUID_HELPER.createFluidTank(capacity, validFluids);
|
||||
fluidTank.setChangeListener(this::sendUpdates);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag tag) {
|
||||
super.saveAdditional(tag);
|
||||
fluidTank.writeToNBT(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag tag) {
|
||||
super.load(tag);
|
||||
fluidTank.readFromNBT(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getCapability(CraterCapabilityHandler handler, @Nullable Direction side) {
|
||||
if (handler == CraterCapabilityHandler.FLUID) {
|
||||
return (Optional<T>) Optional.of(fluidTank);
|
||||
}
|
||||
return super.getCapability(handler, side);
|
||||
}
|
||||
|
||||
public CraterFluidTank getFluidTank() {
|
||||
return fluidTank;
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
package com.hypherionmc.craterlib.common.item;
|
||||
|
||||
import com.hypherionmc.craterlib.api.rendering.DyableBlock;
|
||||
import com.hypherionmc.craterlib.api.rendering.ItemDyable;
|
||||
import com.hypherionmc.craterlib.core.platform.ClientPlatform;
|
||||
import com.hypherionmc.craterlib.core.platform.Platform;
|
||||
import com.hypherionmc.craterlib.core.platform.services.Environment;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Base Item for Blocks that implement @link {DyableBlock}.
|
||||
*/
|
||||
public class BlockItemDyable extends BlockItem implements ItemDyable {
|
||||
|
||||
public BlockItemDyable(Block block, Properties properties) {
|
||||
super(block, properties);
|
||||
|
||||
if (Platform.LOADER.getEnvironment() == Environment.CLIENT) {
|
||||
ClientPlatform.CLIENT_HELPER.registerItemProperty(this, "color");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Item Color from the block
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public DyeColor getColor(ItemStack stack) {
|
||||
return this.getColorFromNBT(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component getName(ItemStack stack) {
|
||||
return Component.translatable(
|
||||
this.getDescriptionId(),
|
||||
WordUtils.capitalizeFully(getColorFromNBT(
|
||||
stack).getName().replace("_", " ")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public DyeColor getColorFromNBT(ItemStack stack) {
|
||||
CompoundTag tag = stack.getOrCreateTag();
|
||||
if (tag.contains("color")) {
|
||||
return DyeColor.byName(tag.getString("color"), DyeColor.BLACK);
|
||||
} else {
|
||||
if (this.getBlock() instanceof DyableBlock dyableBlock) {
|
||||
return dyableBlock.defaultDyeColor();
|
||||
}
|
||||
}
|
||||
return DyeColor.BLACK;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected BlockState getPlacementState(BlockPlaceContext ctx) {
|
||||
BlockState state = this.getBlock().getStateForPlacement(ctx);
|
||||
if (state != null && state.getBlock() instanceof DyableBlock) {
|
||||
Property property = state.getBlock().getStateDefinition().getProperty("color");
|
||||
if (property != null) {
|
||||
state = state.setValue(property, getColorFromNBT(ctx.getItemInHand()));
|
||||
}
|
||||
}
|
||||
return state != null && this.canPlace(ctx, state) ? state : null;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,116 @@
|
||||
package com.hypherionmc.craterlib.common.item;
|
||||
|
||||
import com.hypherionmc.craterlib.api.rendering.ItemDyable;
|
||||
import net.minecraft.advancements.CriteriaTriggers;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.stats.Stats;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.*;
|
||||
import net.minecraft.world.item.alchemy.PotionUtils;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Custom Water Bottle item that supports Dye and can be used as Dye
|
||||
*/
|
||||
public class DyableWaterBottle extends DyeItem implements ItemDyable {
|
||||
|
||||
private final DyeColor color;
|
||||
private final boolean isGlowing;
|
||||
|
||||
public DyableWaterBottle(DyeColor color, boolean isGlowing, Properties properties) {
|
||||
super(color, properties);
|
||||
this.color = color;
|
||||
this.isGlowing = isGlowing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally this is used for enchanted items, in this case, it's used to check if the fluid is a glowing fluid
|
||||
*
|
||||
* @param stack
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isFoil(ItemStack stack) {
|
||||
return this.isGlowing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color of the item for the Color Handler
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public DyeColor getColor(ItemStack stack) {
|
||||
return this.color;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is basically the same as the vanilla method for water bottles
|
||||
*
|
||||
* @param stack
|
||||
* @param level
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity user) {
|
||||
Player playerEntity;
|
||||
Player playerEntity2 = playerEntity = user instanceof Player ? (Player) user : null;
|
||||
if (playerEntity instanceof ServerPlayer) {
|
||||
CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer) playerEntity, stack);
|
||||
}
|
||||
if (!level.isClientSide()) {
|
||||
List<MobEffectInstance> list = PotionUtils.getMobEffects(stack);
|
||||
for (MobEffectInstance statusEffectInstance : list) {
|
||||
if (statusEffectInstance.getEffect().isInstantenous()) {
|
||||
statusEffectInstance.getEffect().applyInstantenousEffect(playerEntity, playerEntity, user, statusEffectInstance.getAmplifier(), 1.0);
|
||||
continue;
|
||||
}
|
||||
user.addEffect(new MobEffectInstance(statusEffectInstance));
|
||||
}
|
||||
if (stack.getItem() == this && isGlowing) {
|
||||
user.addEffect(new MobEffectInstance(MobEffects.NIGHT_VISION, 3600));
|
||||
}
|
||||
}
|
||||
if (playerEntity != null) {
|
||||
playerEntity.awardStat(Stats.ITEM_USED.get(this));
|
||||
if (!playerEntity.getAbilities().instabuild) {
|
||||
stack.shrink(1);
|
||||
}
|
||||
}
|
||||
if (playerEntity == null || !playerEntity.getAbilities().instabuild) {
|
||||
if (stack.isEmpty()) {
|
||||
return new ItemStack(Items.GLASS_BOTTLE);
|
||||
}
|
||||
if (playerEntity != null) {
|
||||
playerEntity.getInventory().add(new ItemStack(Items.GLASS_BOTTLE));
|
||||
}
|
||||
}
|
||||
level.gameEvent(user, GameEvent.DRINK, user.getOnPos());
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUseDuration(ItemStack stack) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UseAnim getUseAnimation(ItemStack stack) {
|
||||
return UseAnim.DRINK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
|
||||
return ItemUtils.startUsingInstantly(level, player, hand);
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.hypherionmc.craterlib.common.item;
|
||||
|
||||
import com.hypherionmc.craterlib.api.rendering.ItemDyable;
|
||||
import net.minecraft.world.item.BucketItem;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A custom water bucket that supports Dye Colors
|
||||
*/
|
||||
public class DyableWaterBucket extends BucketItem implements ItemDyable {
|
||||
|
||||
private final DyeColor color;
|
||||
private final boolean isGlowing;
|
||||
|
||||
public DyableWaterBucket(Fluid fluid, Properties properties, DyeColor color, boolean isGlowing) {
|
||||
super(fluid, properties);
|
||||
this.color = color;
|
||||
this.isGlowing = isGlowing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally this is used for enchanted items, in this case, it's used to check if the fluid is a glowing fluid
|
||||
*
|
||||
* @param stack
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isFoil(ItemStack stack) {
|
||||
return this.isGlowing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DyeColor getColor(ItemStack stack) {
|
||||
return this.color;
|
||||
}
|
||||
|
||||
public boolean isGlowing() {
|
||||
return isGlowing;
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package com.hypherionmc.craterlib.common.particles;
|
||||
|
||||
import net.minecraft.core.particles.SimpleParticleType;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper Class for exposing a hidden constructor in the vanilla particle type
|
||||
*/
|
||||
public class WrappedSimpleParticleType extends SimpleParticleType {
|
||||
|
||||
public WrappedSimpleParticleType(boolean alwaysShow) {
|
||||
super(alwaysShow);
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package com.hypherionmc.craterlib.core.config;
|
||||
|
||||
import com.hypherionmc.craterlib.CraterConstants;
|
||||
import me.hypherionmc.moonconfig.core.file.FileWatcher;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Controls Config File Reloads and Events
|
||||
*/
|
||||
public final class ConfigController implements Serializable {
|
||||
|
||||
/**
|
||||
* Cache of registered configs
|
||||
*/
|
||||
private static final HashMap<Object, FileWatcher> monitoredConfigs = new HashMap<>();
|
||||
|
||||
/**
|
||||
* INTERNAL METHOD - Register and watch the config
|
||||
*
|
||||
* @param config - The config class to register and watch
|
||||
*/
|
||||
static void register_config(ModuleConfig config) {
|
||||
if (monitoredConfigs.containsKey(config)) {
|
||||
CraterConstants.LOG.error("Failed to register " + config.getConfigPath().getName() + ". Config already registered");
|
||||
} else {
|
||||
FileWatcher configWatcher = new FileWatcher();
|
||||
try {
|
||||
configWatcher.setWatch(config.getConfigPath(), () -> {
|
||||
CraterConstants.LOG.info("Sending Reload Event for: " + config.getConfigPath().getName());
|
||||
config.configReloaded();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
CraterConstants.LOG.error("Failed to register " + config.getConfigPath().getName() + " for auto reloading. " + e.getMessage());
|
||||
}
|
||||
monitoredConfigs.put(config, configWatcher);
|
||||
CraterConstants.LOG.info("Registered " + config.getConfigPath().getName() + " successfully!");
|
||||
}
|
||||
}
|
||||
|
||||
public static HashMap<Object, FileWatcher> getMonitoredConfigs() {
|
||||
return monitoredConfigs;
|
||||
}
|
||||
}
|
@@ -0,0 +1,173 @@
|
||||
package com.hypherionmc.craterlib.core.config;
|
||||
|
||||
import me.hypherionmc.moonconfig.core.CommentedConfig;
|
||||
import me.hypherionmc.moonconfig.core.Config;
|
||||
import me.hypherionmc.moonconfig.core.conversion.ObjectConverter;
|
||||
import me.hypherionmc.moonconfig.core.file.CommentedFileConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Base Config class containing the save, upgrading and loading logic.
|
||||
* All config classes must extend this class
|
||||
*/
|
||||
public class ModuleConfig {
|
||||
|
||||
/* Final Variables */
|
||||
private final transient File configPath;
|
||||
private final transient String networkID;
|
||||
|
||||
private final transient String configName;
|
||||
|
||||
private final transient String modId;
|
||||
|
||||
/**
|
||||
* Set up the config
|
||||
*
|
||||
* @param modId - The ID of the Mod/Module the config belongs to
|
||||
* @param configName - The name of the config file, excluding extension
|
||||
*/
|
||||
public ModuleConfig(String modId, String configName) {
|
||||
this(modId, "", configName);
|
||||
}
|
||||
|
||||
public ModuleConfig(String modId, String subFolder, String configName) {
|
||||
/* Preserve the order of the config values */
|
||||
Config.setInsertionOrderPreserved(true);
|
||||
|
||||
/* Configure Paths and Network SYNC ID */
|
||||
File configDir = new File("config" + (subFolder.isEmpty() ? "" : File.separator + subFolder));
|
||||
configPath = new File(configDir + File.separator + configName + ".toml");
|
||||
networkID = modId + ":conf_" + configName.replace("-", "_");
|
||||
this.modId = modId;
|
||||
this.configName = configName;
|
||||
|
||||
/* Check if the required directories exists, otherwise we create them */
|
||||
if (!configDir.exists()) {
|
||||
configDir.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has to be called in the config constructor. This creates or upgrades the config file as needed
|
||||
*
|
||||
* @param config - The config class to use
|
||||
*/
|
||||
public void registerAndSetup(ModuleConfig config) {
|
||||
if (!configPath.exists() || configPath.length() < 2) {
|
||||
saveConfig(config);
|
||||
} else {
|
||||
migrateConfig(config);
|
||||
}
|
||||
/* Register the Config for Watching and events */
|
||||
ConfigController.register_config(this);
|
||||
this.configReloaded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the config to the disk
|
||||
*
|
||||
* @param conf - The config class to serialize and save
|
||||
*/
|
||||
public void saveConfig(ModuleConfig conf) {
|
||||
/* Set up the Serializer and Config Object */
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath).build();
|
||||
|
||||
/* Save the config and fire the reload events */
|
||||
converter.toConfig(conf, config);
|
||||
config.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the config from the file into a Class
|
||||
*
|
||||
* @param conf - The config Class to load
|
||||
* @return - Returns the loaded version of the class
|
||||
*/
|
||||
public <T> T loadConfig(Object conf) {
|
||||
/* Set up the Serializer and Config Object */
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath).build();
|
||||
config.load();
|
||||
|
||||
/* Load the config and return the loaded config */
|
||||
converter.toObject(config, conf);
|
||||
return (T) conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL METHOD - Upgrades the config files in the events the config structure changes
|
||||
*
|
||||
* @param conf - The config class to load
|
||||
*/
|
||||
private void migrateConfig(ModuleConfig conf) {
|
||||
/* Set up the Serializer and Config Objects */
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath).build();
|
||||
CommentedFileConfig newConfig = CommentedFileConfig.builder(configPath).build();
|
||||
config.load();
|
||||
|
||||
/* Upgrade the config */
|
||||
new ObjectConverter().toConfig(conf, newConfig);
|
||||
updateConfigValues(config, newConfig, newConfig, "");
|
||||
newConfig.save();
|
||||
|
||||
config.close();
|
||||
newConfig.close();
|
||||
}
|
||||
|
||||
private void updateConfigValues(CommentedConfig oldConfig, CommentedConfig newConfig, CommentedConfig outputConfig, String subKey) {
|
||||
/* Loop over the config keys and check what has changed */
|
||||
newConfig.valueMap().forEach((key, value) -> {
|
||||
String finalKey = subKey + (subKey.isEmpty() ? "" : ".") + key;
|
||||
if (value instanceof CommentedConfig commentedConfig) {
|
||||
updateConfigValues(oldConfig, commentedConfig, outputConfig, finalKey);
|
||||
} else {
|
||||
outputConfig.set(finalKey,
|
||||
oldConfig.contains(finalKey) ? oldConfig.get(finalKey) : value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location of the config file
|
||||
*
|
||||
* @return - The FILE object containing the config file
|
||||
*/
|
||||
public File getConfigPath() {
|
||||
return configPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the NETWORK SYNC ID
|
||||
*
|
||||
* @return - Returns the Sync ID in format modid:config_name
|
||||
*/
|
||||
public String getNetworkID() {
|
||||
return networkID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired whenever changes to the config are detected
|
||||
*/
|
||||
public void configReloaded() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the Config File
|
||||
* @return
|
||||
*/
|
||||
public String getConfigName() {
|
||||
return configName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MODID of the Module the config is registered to
|
||||
* @return
|
||||
*/
|
||||
public String getModId() {
|
||||
return modId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package com.hypherionmc.craterlib.core.config.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Allows Modules to disable Automatic Config Screens
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NoConfigScreen {
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.hypherionmc.craterlib.core.config.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Used to determine if a Config section should be rendered as a separate screen
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface SubConfig {
|
||||
}
|
||||
|
@@ -0,0 +1,15 @@
|
||||
package com.hypherionmc.craterlib.core.config.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* //TODO Currently unused, but to be used with Config Syncing in the future
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Syncable {
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.hypherionmc.craterlib.core.config.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Provides tooltips to the config GUI
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Tooltip {
|
||||
String[] value();
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.hypherionmc.craterlib.core.event;
|
||||
|
||||
import com.hypherionmc.craterlib.core.event.exception.CraterEventCancellationException;
|
||||
|
||||
public abstract class CraterEvent {
|
||||
|
||||
private boolean canceled = false;
|
||||
|
||||
public abstract boolean canCancel();
|
||||
|
||||
public void cancelEvent() {
|
||||
try {
|
||||
if (!this.canCancel()) {
|
||||
throw new CraterEventCancellationException("Tried to cancel non-cancelable event: " + this.getClass().getName());
|
||||
}
|
||||
|
||||
this.canceled = true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean wasCancelled() {
|
||||
return this.canceled;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,233 @@
|
||||
package com.hypherionmc.craterlib.core.event;
|
||||
|
||||
import com.hypherionmc.craterlib.CraterConstants;
|
||||
import com.hypherionmc.craterlib.core.event.annot.CraterEventListener;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class CraterEventBus {
|
||||
|
||||
private static final Logger LOGGER = CraterConstants.LOG;
|
||||
|
||||
public static final CraterEventBus INSTANCE = new CraterEventBus();
|
||||
private final Map<Class<? extends CraterEvent>, List<ListenerContainer>> events = new HashMap<>();
|
||||
|
||||
public void postEvent(CraterEvent event) {
|
||||
if (eventsRegisteredForType(event.getClass())) {
|
||||
List<ListenerContainer> l = new ArrayList<>(events.get(event.getClass()));
|
||||
l.sort((o1, o2) -> Integer.compare(o2.priority, o1.priority));
|
||||
|
||||
for (ListenerContainer c : l) {
|
||||
c.notifyListener(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerEventListener(Class<?> clazz) {
|
||||
this.registerListenerMethods(this.getEventMethodsOf(clazz));
|
||||
}
|
||||
|
||||
public void registerEventListener(Object object) {
|
||||
this.registerListenerMethods(this.getEventMethodsOf(object));
|
||||
}
|
||||
|
||||
private void registerListenerMethods(List<EventMethod> methods) {
|
||||
for (EventMethod m : methods) {
|
||||
Consumer<CraterEvent> listener = (event) -> {
|
||||
try {
|
||||
m.method.invoke(m.parentObject, event);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
};
|
||||
|
||||
ListenerContainer container = new ListenerContainer(m.eventType, listener, m.priority);
|
||||
container.listenerParentClassName = m.parentClass.getName();
|
||||
container.listenerMethodName = m.method.getName();
|
||||
this.registerListener(container);
|
||||
}
|
||||
}
|
||||
|
||||
private List<EventMethod> getEventMethodsOf(Object objectOrClass) {
|
||||
List<EventMethod> l = new ArrayList<>();
|
||||
try {
|
||||
if (objectOrClass != null) {
|
||||
boolean isClass = (objectOrClass instanceof Class<?>);
|
||||
Class<?> c = isClass ? (Class<?>) objectOrClass : objectOrClass.getClass();
|
||||
for (Method m : c.getMethods()) {
|
||||
if (isClass && Modifier.isStatic(m.getModifiers())) {
|
||||
EventMethod em = EventMethod.tryCreateFrom(new AnalyzedMethod(m, c));
|
||||
if (em != null) l.add(em);
|
||||
}
|
||||
if (!isClass && !Modifier.isStatic(m.getModifiers())) {
|
||||
EventMethod em = EventMethod.tryCreateFrom(new AnalyzedMethod(m, objectOrClass));
|
||||
if (em != null) l.add(em);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public void registerListener(Consumer<CraterEvent> listener, Class<? extends CraterEvent> eventType) {
|
||||
this.registerListener(listener, eventType, 0);
|
||||
}
|
||||
|
||||
public void registerListener(Consumer<CraterEvent> listener, Class<? extends CraterEvent> eventType, int priority) {
|
||||
this.registerListener(new ListenerContainer(eventType, listener, priority));
|
||||
}
|
||||
|
||||
private void registerListener(ListenerContainer listenerContainer) {
|
||||
try {
|
||||
if (!eventsRegisteredForType(listenerContainer.eventType)) {
|
||||
events.put(listenerContainer.eventType, new ArrayList<>());
|
||||
}
|
||||
events.get(listenerContainer.eventType).add(listenerContainer);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean eventsRegisteredForType(Class<? extends CraterEvent> eventType) {
|
||||
if (eventType == null) {
|
||||
return false;
|
||||
}
|
||||
return this.events.containsKey(eventType);
|
||||
}
|
||||
|
||||
protected final static class ListenerContainer {
|
||||
|
||||
private final Consumer<CraterEvent> listener;
|
||||
private final Class<? extends CraterEvent> eventType;
|
||||
private final int priority;
|
||||
private String listenerParentClassName = "[unknown]";
|
||||
private String listenerMethodName = "[unknown]";
|
||||
|
||||
private ListenerContainer(Class<? extends CraterEvent> eventType, Consumer<CraterEvent> listener, int priority) {
|
||||
this.eventType = eventType;
|
||||
this.listener = listener;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
private void notifyListener(CraterEvent event) {
|
||||
try {
|
||||
this.listener.accept(event);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("##################################");
|
||||
LOGGER.error("Failed to notify event listener!");
|
||||
LOGGER.error("Event Type: " + this.eventType.getName());
|
||||
LOGGER.error("Listener Parent Class Name: " + this.listenerParentClassName);
|
||||
LOGGER.error("Listener Method Name In Parent Class: " + this.listenerMethodName);
|
||||
LOGGER.error("##################################");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static class AnalyzedMethod {
|
||||
|
||||
protected Method method;
|
||||
protected Object parentObject;
|
||||
protected Class<?> parentClass;
|
||||
protected boolean isStatic;
|
||||
protected List<Annotation> annotations = new ArrayList<>();
|
||||
|
||||
protected AnalyzedMethod() {
|
||||
}
|
||||
|
||||
protected AnalyzedMethod(Method method, Object parentObjectOrClass) {
|
||||
this.method = method;
|
||||
this.parentObject = parentObjectOrClass;
|
||||
this.parentClass = this.tryGetParentClass();
|
||||
this.isStatic = Modifier.isStatic(method.getModifiers());
|
||||
collectMethodAnnotations(this.isStatic ? null : this.parentObject.getClass(), this.method, this.annotations);
|
||||
}
|
||||
|
||||
protected Class<?> tryGetParentClass() {
|
||||
if (this.parentObject instanceof Class<?>) {
|
||||
return (Class<?>) this.parentObject;
|
||||
}
|
||||
return this.parentObject.getClass();
|
||||
}
|
||||
|
||||
protected static void collectMethodAnnotations(Class<?> c, Method m, List<Annotation> addToList) {
|
||||
try {
|
||||
addToList.addAll(Arrays.asList(m.getAnnotations()));
|
||||
if (!Modifier.isStatic(m.getModifiers()) && (c != null)) {
|
||||
Class<?> sc = c.getSuperclass();
|
||||
if (sc != null) {
|
||||
try {
|
||||
Method sm = sc.getMethod(m.getName(), m.getParameterTypes());
|
||||
collectMethodAnnotations(sc, sm, addToList);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class EventMethod extends AnalyzedMethod {
|
||||
|
||||
protected final int priority;
|
||||
protected final Class<? extends CraterEvent> eventType;
|
||||
|
||||
protected static EventMethod tryCreateFrom(AnalyzedMethod method) {
|
||||
EventMethod em = new EventMethod(method);
|
||||
return (em.eventType != null) ? em : null;
|
||||
}
|
||||
|
||||
protected EventMethod(AnalyzedMethod method) {
|
||||
|
||||
super();
|
||||
this.method = method.method;
|
||||
this.parentObject = method.parentObject;
|
||||
this.parentClass = method.parentClass;
|
||||
this.isStatic = method.isStatic;
|
||||
this.annotations = method.annotations;
|
||||
|
||||
this.priority = this.tryGetPriority();
|
||||
this.eventType = this.tryGetEventType();
|
||||
|
||||
}
|
||||
|
||||
protected Class<? extends CraterEvent> tryGetEventType() {
|
||||
try {
|
||||
if (this.method != null) {
|
||||
Class<?>[] params = this.method.getParameterTypes();
|
||||
if (params.length > 0) {
|
||||
Class<?> firstParam = params[0];
|
||||
if (CraterEvent.class.isAssignableFrom(firstParam)) {
|
||||
return (Class<? extends CraterEvent>) firstParam;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected int tryGetPriority() {
|
||||
try {
|
||||
for (Annotation a : this.annotations) {
|
||||
if (a instanceof CraterEventListener craterEventListener) {
|
||||
return craterEventListener.priority();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package com.hypherionmc.craterlib.core.event;
|
||||
|
||||
public class CraterEventPriority {
|
||||
|
||||
public static final int LOWEST = -3;
|
||||
public static final int LOWER = -2;
|
||||
public static final int LOW = -1;
|
||||
public static final int NORMAL = 0;
|
||||
public static final int HIGH = 1;
|
||||
public static final int HIGHER = 2;
|
||||
public static final int HIGHEST = 3;
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.hypherionmc.craterlib.core.event.annot;
|
||||
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventPriority;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CraterEventListener {
|
||||
int priority() default CraterEventPriority.NORMAL;
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package com.hypherionmc.craterlib.core.event.exception;
|
||||
|
||||
public class CraterEventCancellationException extends Exception {
|
||||
|
||||
public CraterEventCancellationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* The event system code in this package is based on, and adapted from Acara (https://github.com/Keksuccino/acara/)
|
||||
* and is licensed under MIT by Keksuccino
|
||||
*/
|
||||
package com.hypherionmc.craterlib.core.event;
|
@@ -0,0 +1,33 @@
|
||||
package com.hypherionmc.craterlib.core.network;
|
||||
|
||||
import com.hypherionmc.craterlib.core.platform.ClientPlatform;
|
||||
import com.hypherionmc.craterlib.core.platform.Platform;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public interface CraterNetworkHandler {
|
||||
|
||||
<T extends CraterPacket<T>> void registerPacket(Class<? extends T> clazz, Supplier<T> supplier, PacketDirection packetDirection);
|
||||
|
||||
Packet<?> toServerBound(CraterPacket<?> packet);
|
||||
|
||||
Packet<?> toClientBound(CraterPacket<?> packet);
|
||||
|
||||
default void sendToServer(CraterPacket<?> packet) {
|
||||
ClientPlatform.CLIENT_HELPER.getClientConnection().send(this.toServerBound(packet));
|
||||
}
|
||||
|
||||
default void sendTo(CraterPacket<?> packet, ServerPlayer player) {
|
||||
player.connection.send(this.toClientBound(packet));
|
||||
}
|
||||
|
||||
default void sendToAll(CraterPacket<?> packet) {
|
||||
Platform.COMMON_HELPER.getMCServer().getPlayerList().broadcastAll(this.toClientBound(packet));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.hypherionmc.craterlib.core.network;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public interface CraterPacket<T extends CraterPacket<T>> {
|
||||
|
||||
void write(final FriendlyByteBuf buf);
|
||||
|
||||
void read(final FriendlyByteBuf buf);
|
||||
|
||||
default void handle(Player player, Object minecraft) {
|
||||
this.createHandler().handle((T) this, player, minecraft);
|
||||
}
|
||||
|
||||
PacketHandler<T> createHandler();
|
||||
|
||||
abstract class PacketHandler<T extends CraterPacket<T>> {
|
||||
public abstract void handle(T packet, Player player, Object minecraft);
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package com.hypherionmc.craterlib.core.network;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public enum PacketDirection {
|
||||
TO_SERVER,
|
||||
TO_CLIENT
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package com.hypherionmc.craterlib.core.platform;
|
||||
|
||||
import com.hypherionmc.craterlib.CraterConstants;
|
||||
import com.hypherionmc.craterlib.core.platform.services.LibClientHelper;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public class ClientPlatform {
|
||||
|
||||
public static final LibClientHelper CLIENT_HELPER = load(LibClientHelper.class);
|
||||
|
||||
public static <T> T load(Class<T> clazz) {
|
||||
|
||||
final T loadedService = ServiceLoader.load(clazz)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
|
||||
CraterConstants.LOG.debug("Loaded {} for service {}", loadedService, clazz);
|
||||
return loadedService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.hypherionmc.craterlib.core.platform;
|
||||
|
||||
import com.hypherionmc.craterlib.CraterConstants;
|
||||
import com.hypherionmc.craterlib.core.platform.services.ILoaderHelper;
|
||||
import com.hypherionmc.craterlib.core.platform.services.LibCommonHelper;
|
||||
import com.hypherionmc.craterlib.core.platform.services.LibFluidHelper;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public class Platform {
|
||||
|
||||
public static final ILoaderHelper LOADER = load(ILoaderHelper.class);
|
||||
|
||||
public static final LibCommonHelper COMMON_HELPER = load(LibCommonHelper.class);
|
||||
|
||||
public static final LibFluidHelper FLUID_HELPER = load(LibFluidHelper.class);
|
||||
|
||||
public static <T> T load(Class<T> clazz) {
|
||||
|
||||
final T loadedService = ServiceLoader.load(clazz)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
|
||||
CraterConstants.LOG.debug("Loaded {} for service {}", loadedService, clazz);
|
||||
return loadedService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package com.hypherionmc.craterlib.core.platform.services;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public enum Environment {
|
||||
CLIENT,
|
||||
SERVER,
|
||||
UNKNOWN
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package com.hypherionmc.craterlib.core.platform.services;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper class to provide information about the ModLoader
|
||||
*/
|
||||
public interface ILoaderHelper {
|
||||
|
||||
boolean isFabric();
|
||||
String getGameVersion();
|
||||
File getGameFolder();
|
||||
File getConfigFolder();
|
||||
File getModsFolder();
|
||||
Environment getEnvironment();
|
||||
boolean isModLoaded(String modid);
|
||||
boolean isDevEnv();
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package com.hypherionmc.craterlib.core.platform.services;
|
||||
|
||||
import com.hypherionmc.craterlib.common.item.BlockItemDyable;
|
||||
import com.hypherionmc.craterlib.core.network.CraterPacket;
|
||||
import me.hypherionmc.craterlib.systems.reg.RegistryObject;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public interface LibClientHelper {
|
||||
|
||||
void registerItemProperty(@NotNull BlockItemDyable item, @NotNull String property);
|
||||
|
||||
void registerCustomRenderTypes(
|
||||
@NotNull Collection<RegistryObject<Block>> blocks,
|
||||
@NotNull Collection<RegistryObject<Item>> items
|
||||
);
|
||||
|
||||
Minecraft getClientInstance();
|
||||
|
||||
Player getClientPlayer();
|
||||
|
||||
Level getClientLevel();
|
||||
|
||||
Connection getClientConnection();
|
||||
|
||||
void registerClientReceiver(@NotNull ResourceLocation channelName, @NotNull Function<FriendlyByteBuf, @NotNull CraterPacket<?>> factory);
|
||||
|
||||
void registerBlockEntityRenderer(@NotNull BlockEntityType<? extends BlockEntity> blockEntityType, @NotNull BlockEntityRendererProvider blockEntityRendererFactory);
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package com.hypherionmc.craterlib.core.platform.services;
|
||||
|
||||
import com.hypherionmc.craterlib.api.blockentity.caps.CraterCapabilityHandler;
|
||||
import com.hypherionmc.craterlib.core.network.CraterNetworkHandler;
|
||||
import com.hypherionmc.craterlib.core.network.CraterPacket;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.apache.commons.lang3.function.TriFunction;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public interface LibCommonHelper {
|
||||
|
||||
CraterNetworkHandler createPacketHandler(String modid);
|
||||
|
||||
MinecraftServer getMCServer();
|
||||
|
||||
void openMenu(ServerPlayer player, MenuProvider menu, @Nullable Consumer<FriendlyByteBuf> initialData);
|
||||
|
||||
<T extends AbstractContainerMenu> MenuType<T> createMenuType(TriFunction<Integer, Inventory, FriendlyByteBuf, T> constructor);
|
||||
|
||||
/* FABRIC ONLY */
|
||||
void registerServerReceiver(ResourceLocation channelName, Function<FriendlyByteBuf, CraterPacket<?>> factory);
|
||||
|
||||
<T> Optional<T> getCapabilityHandler(BlockEntity entity, Direction side, CraterCapabilityHandler capability);
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.hypherionmc.craterlib.core.platform.services;
|
||||
|
||||
import com.hypherionmc.craterlib.core.systems.fluid.CraterFluidTank;
|
||||
import com.hypherionmc.craterlib.core.systems.fluid.FluidHolder;
|
||||
import com.hypherionmc.craterlib.core.systems.fluid.ICraterFluidHandler;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public interface LibFluidHelper {
|
||||
|
||||
CraterFluidTank createFluidTank(int capacity);
|
||||
|
||||
CraterFluidTank createFluidTank(int capacity, Fluid... validFluids);
|
||||
|
||||
boolean interactWithFluidHandler(Player player, InteractionHand hand, ICraterFluidHandler fluidHandler);
|
||||
|
||||
boolean interactWithFluidHandler(@NotNull Player player, @NotNull InteractionHand hand, @NotNull Level level, @NotNull BlockPos pos, @Nullable Direction side);
|
||||
|
||||
TextureAtlasSprite getFluidTexture(FluidHolder fluidHolder);
|
||||
|
||||
int getFluidColor(Fluid fluid);
|
||||
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
package com.hypherionmc.craterlib.core.systems.energy;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
/***
|
||||
* @author HypherionSA
|
||||
* Loosely based on the Forge Energy System
|
||||
*/
|
||||
public class CustomEnergyStorage implements ICraterEnergyStorage {
|
||||
|
||||
protected int powerLevel;
|
||||
protected int powerCapacity;
|
||||
protected int maxInput;
|
||||
protected int maxOutput;
|
||||
|
||||
public CustomEnergyStorage(int capacity) {
|
||||
this(capacity, capacity, capacity, 0);
|
||||
}
|
||||
|
||||
public CustomEnergyStorage(int powerCapacity, int maxTransfer) {
|
||||
this(powerCapacity, maxTransfer, maxTransfer, 0);
|
||||
}
|
||||
|
||||
public CustomEnergyStorage(int powerCapacity, int maxInput, int maxOutput) {
|
||||
this(powerCapacity, maxInput, maxOutput, 0);
|
||||
}
|
||||
|
||||
public CustomEnergyStorage(int capacity, int maxInput, int maxOutput, int initialPower) {
|
||||
this.powerLevel = initialPower;
|
||||
this.maxInput = maxInput;
|
||||
this.maxOutput = maxOutput;
|
||||
this.powerCapacity = capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag writeNBT(CompoundTag compoundTag) {
|
||||
compoundTag.putInt("powerLevel", this.powerLevel);
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(CompoundTag compoundTag) {
|
||||
if (compoundTag.contains("powerLevel")) {
|
||||
this.powerLevel = compoundTag.getInt("powerLevel");
|
||||
}
|
||||
}
|
||||
|
||||
public int receiveEnergyInternal(int toReceive, boolean test) {
|
||||
int energyReceived = Math.min(this.powerCapacity - this.powerLevel, Math.min(this.maxInput, toReceive));
|
||||
if (!test)
|
||||
this.powerLevel += energyReceived;
|
||||
return energyReceived;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int receiveEnergy(int toReceive, boolean test) {
|
||||
if (this.maxInput < 1) {
|
||||
return 0;
|
||||
}
|
||||
return this.receiveEnergyInternal(toReceive, test);
|
||||
}
|
||||
|
||||
public int extractEnergyInternal(int toExtract, boolean test) {
|
||||
int energyExtracted = Math.min(this.powerLevel, Math.min(this.powerCapacity, toExtract));
|
||||
if (!test)
|
||||
this.powerLevel -= energyExtracted;
|
||||
return energyExtracted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int extractEnergy(int toExtract, boolean test) {
|
||||
if (this.maxOutput < 1) {
|
||||
return 0;
|
||||
}
|
||||
int energyExtracted = Math.min(this.powerLevel, Math.min(this.maxOutput, toExtract));
|
||||
if (!test)
|
||||
this.powerLevel -= energyExtracted;
|
||||
return energyExtracted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPowerLevel() {
|
||||
return powerLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxInput() {
|
||||
return maxInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxOutput() {
|
||||
return maxOutput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPowerCapacity() {
|
||||
return powerCapacity;
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.hypherionmc.craterlib.core.systems.energy;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public interface ICraterEnergyStorage {
|
||||
|
||||
default CompoundTag writeNBT(CompoundTag tag) { return tag; }
|
||||
default void readNBT(CompoundTag tag) {}
|
||||
|
||||
int receiveEnergy(int toReceive, boolean test);
|
||||
int extractEnergy(int toExtract, boolean test);
|
||||
|
||||
int getPowerLevel();
|
||||
|
||||
int getMaxInput();
|
||||
|
||||
int getMaxOutput();
|
||||
|
||||
int getPowerCapacity();
|
||||
|
||||
}
|
@@ -0,0 +1,151 @@
|
||||
package com.hypherionmc.craterlib.core.systems.fluid;
|
||||
|
||||
import com.hypherionmc.craterlib.util.FluidUtils;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A cross Modloader FluidTank implementation
|
||||
*/
|
||||
public class CraterFluidTank implements ICraterFluidHandler {
|
||||
|
||||
private final int capacity;
|
||||
private final Predicate<FluidHolder> validFluid;
|
||||
private FluidHolder fluid = FluidHolder.EMPTY;
|
||||
|
||||
private ChangeListener contentsChanged;
|
||||
|
||||
public CraterFluidTank(int capacity) {
|
||||
this(capacity, e -> true);
|
||||
}
|
||||
|
||||
public CraterFluidTank(int capacity, Predicate<FluidHolder> validFluid) {
|
||||
this.capacity = capacity;
|
||||
this.validFluid = validFluid;
|
||||
}
|
||||
|
||||
public boolean isValidFluid(FluidHolder variant) {
|
||||
return validFluid.test(variant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insert(FluidHolder fluidHolder, FluidAction action) {
|
||||
if (fluidHolder.isEmpty() || !isValidFluid(fluidHolder)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (action.simulate()) {
|
||||
if (fluid.isEmpty()) {
|
||||
return Math.min(capacity, fluidHolder.getAmount());
|
||||
}
|
||||
if (!fluid.isFluidEqual(fluidHolder)) {
|
||||
return 0;
|
||||
}
|
||||
return Math.min(capacity - fluid.getAmount(), fluidHolder.getAmount());
|
||||
}
|
||||
|
||||
if (fluid.isEmpty()) {
|
||||
fluid = new FluidHolder(fluidHolder.getFluid(), Math.min(capacity, fluidHolder.getAmount()));
|
||||
return fluid.getAmount();
|
||||
}
|
||||
if (!fluid.isFluidEqual(fluidHolder)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filled = capacity - fluid.getAmount();
|
||||
|
||||
if (fluidHolder.getAmount() < filled) {
|
||||
fluid.grow(fluidHolder.getAmount());
|
||||
filled = fluidHolder.getAmount();
|
||||
} else {
|
||||
fluid.setAmount(capacity);
|
||||
filled = capacity;
|
||||
}
|
||||
|
||||
if (filled > 0) {
|
||||
if (contentsChanged != null) {
|
||||
contentsChanged.onContentsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
return filled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidHolder extract(FluidHolder resource, FluidAction action) {
|
||||
if (resource.isEmpty() || !resource.isFluidEqual(fluid)) {
|
||||
return FluidHolder.EMPTY;
|
||||
}
|
||||
return extract(resource.getAmount(), action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidHolder extract(int amount, FluidAction action) {
|
||||
int drained = amount;
|
||||
if (fluid.getAmount() < drained) {
|
||||
drained = fluid.getAmount();
|
||||
}
|
||||
|
||||
FluidHolder holder = new FluidHolder(fluid, drained);
|
||||
|
||||
if (action.execute() && drained > 0) {
|
||||
fluid.shrink(drained);
|
||||
}
|
||||
|
||||
if (contentsChanged != null) {
|
||||
contentsChanged.onContentsChanged();
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
|
||||
public void setContainedFluid(FluidHolder fluid) {
|
||||
this.fluid = fluid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTankEmpty() {
|
||||
return fluid.isEmpty();
|
||||
}
|
||||
|
||||
public int getSpace()
|
||||
{
|
||||
return Math.max(0, capacity - fluid.getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidHolder getFluidInTank() {
|
||||
return fluid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankLevel() {
|
||||
return fluid.getAmount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag writeToNBT(CompoundTag tag) {
|
||||
FluidUtils.putFluid(tag, "fluid", fluid.getFluid());
|
||||
tag.putInt("tankLevel", fluid.getAmount());
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(CompoundTag tag) {
|
||||
fluid = new FluidHolder(FluidUtils.getFluidCompatible(tag), tag.getInt("tankLevel"));
|
||||
}
|
||||
|
||||
public void setChangeListener(ChangeListener contentsChanged) {
|
||||
this.contentsChanged = contentsChanged;
|
||||
}
|
||||
|
||||
public interface ChangeListener {
|
||||
void onContentsChanged();
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
package com.hypherionmc.craterlib.core.systems.fluid;
|
||||
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Cross Modloader "FluidStack" implementation
|
||||
*/
|
||||
public class FluidHolder {
|
||||
|
||||
private final Fluid fluid;
|
||||
private int amount;
|
||||
|
||||
public FluidHolder(FluidHolder holder) {
|
||||
this(holder.getFluid(), holder.getAmount());
|
||||
}
|
||||
|
||||
public FluidHolder(Fluid fluid, int amount) {
|
||||
this.fluid = fluid;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public FluidHolder(FluidHolder fluid, int amount) {
|
||||
this.fluid = fluid.getFluid();
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public static FluidHolder EMPTY = new FluidHolder(Fluids.EMPTY, 0);
|
||||
|
||||
public boolean isEmpty() {
|
||||
return amount == 0 || fluid.isSame(Fluids.EMPTY);
|
||||
}
|
||||
|
||||
public Fluid getFluid() {
|
||||
return fluid;
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public boolean isFluidEqual(@NotNull FluidHolder other)
|
||||
{
|
||||
return this.getFluid() == other.getFluid();
|
||||
}
|
||||
|
||||
public void grow(int amount) {
|
||||
this.amount += amount;
|
||||
}
|
||||
|
||||
public void setAmount(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void shrink(int amount) {
|
||||
this.amount -= amount;
|
||||
}
|
||||
|
||||
public FluidHolder copy() {
|
||||
return new FluidHolder(getFluid(), getAmount());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package com.hypherionmc.craterlib.core.systems.fluid;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Cross modloader fluid handler implementation
|
||||
*/
|
||||
public interface ICraterFluidHandler {
|
||||
|
||||
enum FluidAction {
|
||||
EXECUTE,
|
||||
SIMULATE;
|
||||
|
||||
public boolean simulate() {
|
||||
return this == SIMULATE;
|
||||
}
|
||||
|
||||
public boolean execute() {
|
||||
return this == EXECUTE;
|
||||
}
|
||||
}
|
||||
|
||||
int insert(FluidHolder fluidHolder, CraterFluidTank.FluidAction action);
|
||||
FluidHolder extract(FluidHolder fluidHolder, CraterFluidTank.FluidAction action);
|
||||
FluidHolder extract(int amount, CraterFluidTank.FluidAction action);
|
||||
boolean isTankEmpty();
|
||||
FluidHolder getFluidInTank();
|
||||
int getTankLevel();
|
||||
int getTankCapacity();
|
||||
|
||||
default CompoundTag writeToNBT(CompoundTag tag) { return tag; }
|
||||
|
||||
default void readFromNBT(CompoundTag tag) {};
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
package com.hypherionmc.craterlib.core.systems.internal;
|
||||
|
||||
import com.hypherionmc.craterlib.api.creativetab.CraterCreativeModeTab;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A helper class to make registering creative tabs easier across modloaders
|
||||
*/
|
||||
public class CreativeTabRegistry {
|
||||
|
||||
private static final List<CraterCreativeModeTab> TABS = new ArrayList<>();
|
||||
private static final List<Pair<CraterCreativeModeTab, Supplier<? extends ItemLike>>> TAB_ITEMS = new ArrayList<>();
|
||||
|
||||
public static void setCreativeTab(CraterCreativeModeTab tab, Supplier<? extends ItemLike> item) {
|
||||
if (item != null) {
|
||||
TAB_ITEMS.add(Pair.of(tab, item));
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerTab(CraterCreativeModeTab tab) {
|
||||
TABS.add(tab);
|
||||
}
|
||||
|
||||
public static List<CraterCreativeModeTab> getTabs() {
|
||||
return TABS;
|
||||
}
|
||||
|
||||
public static List<Pair<CraterCreativeModeTab, Supplier<? extends ItemLike>>> getTabItems() {
|
||||
return TAB_ITEMS;
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
package com.hypherionmc.craterlib.core.systems.inventory;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.Clearable;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* A crossmodloader inventory implementation
|
||||
*/
|
||||
public class SimpleInventory implements Clearable {
|
||||
|
||||
private final SimpleContainer itemHandler;
|
||||
private final int size;
|
||||
|
||||
private final int stackSize;
|
||||
|
||||
public SimpleInventory(int size, int maxStackSize) {
|
||||
itemHandler = new SimpleContainer(size) {
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return maxStackSize;
|
||||
}
|
||||
};
|
||||
this.size = size;
|
||||
this.stackSize = maxStackSize;
|
||||
}
|
||||
|
||||
private static void copyToInv(NonNullList<ItemStack> src, Container dest) {
|
||||
Preconditions.checkArgument(src.size() == dest.getContainerSize());
|
||||
for (int i = 0; i < src.size(); i++) {
|
||||
dest.setItem(i, src.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
private static NonNullList<ItemStack> copyFromInv(Container inv) {
|
||||
NonNullList<ItemStack> ret = NonNullList.withSize(inv.getContainerSize(), ItemStack.EMPTY);
|
||||
for (int i = 0; i < inv.getContainerSize(); i++) {
|
||||
ret.set(i, inv.getItem(i));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void readNBT(CompoundTag tag) {
|
||||
NonNullList<ItemStack> tmp = NonNullList.withSize(size, ItemStack.EMPTY);
|
||||
ContainerHelper.loadAllItems(tag, tmp);
|
||||
copyToInv(tmp, itemHandler);
|
||||
}
|
||||
|
||||
public void writeNBT(CompoundTag tag) {
|
||||
ContainerHelper.saveAllItems(tag, copyFromInv(itemHandler));
|
||||
}
|
||||
|
||||
public final int inventorySize() {
|
||||
return getItemHandler().getContainerSize();
|
||||
}
|
||||
|
||||
public int getStackSize() {
|
||||
return stackSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearContent() {
|
||||
getItemHandler().clearContent();
|
||||
}
|
||||
|
||||
public final Container getItemHandler() {
|
||||
return itemHandler;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* So, if you got here, most probably you want to see the registration system of this mod.
|
||||
* Well, you are in the wrong place.
|
||||
* This mod uses <a href="https://github.com/Matyrobbrt/RegistrationUtils">RegistrationUtils</a> for
|
||||
* all its registration needs.
|
||||
*/
|
||||
package com.hypherionmc.craterlib.core.systems.reg;
|
@@ -0,0 +1,27 @@
|
||||
package com.hypherionmc.craterlib.mixin.colors;
|
||||
|
||||
import com.hypherionmc.craterlib.api.event.client.ColorRegistrationEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Mixin to accommodate Block Color Registration across multiple Modloaders
|
||||
*/
|
||||
@Mixin(BlockColors.class)
|
||||
public class BlockColorsMixin {
|
||||
|
||||
/**
|
||||
* Inject into Vanilla code to fire off our event
|
||||
*/
|
||||
@Inject(method = "createDefault", at = @At("RETURN"))
|
||||
private static void injectBlockColors(CallbackInfoReturnable<BlockColors> cir) {
|
||||
ColorRegistrationEvent.Blocks blockEvent = new ColorRegistrationEvent.Blocks(cir.getReturnValue());
|
||||
CraterEventBus.INSTANCE.postEvent(blockEvent);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.hypherionmc.craterlib.mixin.colors;
|
||||
|
||||
import com.hypherionmc.craterlib.api.event.client.ColorRegistrationEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.color.item.ItemColors;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Mixin to accommodate Item Color Registration across multiple Modloaders
|
||||
*/
|
||||
@Mixin(ItemColors.class)
|
||||
public class ItemColorsMixin {
|
||||
|
||||
/**
|
||||
* Inject into Vanilla code to fire off our event
|
||||
* @param cir
|
||||
*/
|
||||
@Inject(method = "createDefault", at = @At("RETURN"))
|
||||
private static void injectItemColors(BlockColors $$0, CallbackInfoReturnable<ItemColors> cir) {
|
||||
ColorRegistrationEvent.Items itemColorEvent = new ColorRegistrationEvent.Items(cir.getReturnValue());
|
||||
CraterEventBus.INSTANCE.postEvent(itemColorEvent);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.hypherionmc.craterlib.util;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Helper class to create light levels from BlockState values
|
||||
*/
|
||||
public class BlockStateUtils {
|
||||
|
||||
public static ToIntFunction<BlockState> lightLevelFromLitBlockState(int litLevel) {
|
||||
return state -> state.getValue(BlockStateProperties.LIT) ? litLevel : 0;
|
||||
}
|
||||
|
||||
public static ToIntFunction<BlockState> lightLevelFromPoweredBlockState(int litLevel) {
|
||||
return state -> state.getValue(BlockStateProperties.POWERED) ? litLevel : 0;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package com.hypherionmc.craterlib.util;
|
||||
|
||||
import com.hypherionmc.craterlib.common.item.BlockItemDyable;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.item.ClampedItemPropertyFunction;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
*/
|
||||
public class ColorPropertyFunction implements ClampedItemPropertyFunction {
|
||||
|
||||
private final BlockItemDyable item;
|
||||
|
||||
public ColorPropertyFunction(BlockItemDyable item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float call(ItemStack itemStack, @Nullable ClientLevel clientLevel, @Nullable LivingEntity livingEntity, int i) {
|
||||
return Mth.clamp(this.unclampedCall(itemStack, clientLevel, livingEntity, i), 0.0F, 15.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float unclampedCall(ItemStack itemStack, @Nullable ClientLevel clientLevel, @Nullable LivingEntity livingEntity, int i) {
|
||||
DyeColor color = item.getColorFromNBT(itemStack);
|
||||
return color.getId();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package com.hypherionmc.craterlib.util;
|
||||
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Utility class for interacting with fluids across modloaders
|
||||
*/
|
||||
public class FluidUtils {
|
||||
|
||||
public static int fluidColorFromDye(DyeColor color) {
|
||||
return color.getMaterialColor().col | 0xFF000000;
|
||||
}
|
||||
|
||||
public static void putFluid(CompoundTag compound, String key, Fluid fluidVariant) {
|
||||
compound.putString("tankFluid", BuiltInRegistries.FLUID.getKey(fluidVariant).toString());
|
||||
}
|
||||
|
||||
public static Fluid getFluidCompatible(CompoundTag tag) {
|
||||
if (tag == null || !tag.contains("tankFluid"))
|
||||
return Fluids.EMPTY;
|
||||
|
||||
return BuiltInRegistries.FLUID.get(new ResourceLocation(tag.getString("tankFluid")));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package com.hypherionmc.craterlib.util;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Utility class to handle Translation Keys and Formatting
|
||||
*/
|
||||
public class LangUtils {
|
||||
|
||||
public static Component getTooltipTitle(String key) {
|
||||
return Component.literal(ChatFormatting.YELLOW + Component.translatable(key).getString());
|
||||
}
|
||||
|
||||
public static String resolveTranslation(String key) {
|
||||
return Component.translatable(key).getString();
|
||||
}
|
||||
|
||||
public static Component getTranslation(String key) {
|
||||
return Component.translatable(key);
|
||||
}
|
||||
|
||||
public static Component makeComponent(String text) {
|
||||
return Component.translatable(text);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package com.hypherionmc.craterlib.util;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Utility class to handle various mathematical functions
|
||||
*/
|
||||
public class MathUtils {
|
||||
|
||||
public static VoxelShape rotateShape(Direction from, Direction to, VoxelShape shape) {
|
||||
VoxelShape[] buffer = new VoxelShape[]{shape, Shapes.empty()};
|
||||
|
||||
int times = (to.ordinal() - from.ordinal() + 4) % 4;
|
||||
for (int i = 0; i < times; i++) {
|
||||
buffer[0].forAllBoxes((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = Shapes.or(buffer[1], Shapes.box(1 - maxZ, minY, minX, 1 - minZ, maxY, maxX)));
|
||||
buffer[0] = buffer[1];
|
||||
buffer[1] = Shapes.empty();
|
||||
}
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
public static void writeBlockPosToNBT(BlockPos pos, CompoundTag tag) {
|
||||
tag.putInt("block_x", pos.getX());
|
||||
tag.putInt("block_y", pos.getY());
|
||||
tag.putInt("block_z", pos.getZ());
|
||||
}
|
||||
|
||||
public static BlockPos readBlockPosFromNBT(CompoundTag tag) {
|
||||
int x, y, z;
|
||||
x = tag.getInt("block_x");
|
||||
y = tag.getInt("block_y");
|
||||
z = tag.getInt("block_z");
|
||||
return new BlockPos(x, y, z);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package com.hypherionmc.craterlib.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Utility class for Optifine compatibility
|
||||
*/
|
||||
public class OptifineUtils {
|
||||
|
||||
private static final boolean hasOptifine = checkOptifine();
|
||||
|
||||
private static boolean checkOptifine() {
|
||||
try {
|
||||
Class<?> ofConfigClass = Class.forName("net.optifine.Config");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Optifine is probably not present. Ignore the error
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isRenderRegions() {
|
||||
try {
|
||||
Class<?> ofConfigClass = Class.forName("net.optifine.Config");
|
||||
Method rrField = ofConfigClass.getMethod("isRenderRegions");
|
||||
return (boolean) rrField.invoke(null);
|
||||
} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException |
|
||||
IllegalAccessException e) {
|
||||
// Optifine is probably not present. Ignore the error
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasOptifine() {
|
||||
return hasOptifine;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
package com.hypherionmc.craterlib.util;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author HypherionSA
|
||||
* Utility class for various rendering functions
|
||||
*/
|
||||
public class RenderUtils {
|
||||
|
||||
public static Vector4f colorIntToRGBA(int color) {
|
||||
float a = 1.0F;
|
||||
float r = (color >> 16 & 0xFF) / 255.0F;
|
||||
float g = (color >> 8 & 0xFF) / 255.0F;
|
||||
float b = (color & 0xFF) / 255.0F;
|
||||
|
||||
return new Vector4f(r, g, b, a);
|
||||
}
|
||||
|
||||
public static Component getFluidAmount(long amount, long capacity) {
|
||||
amount = amount / 81;
|
||||
capacity = capacity / 81;
|
||||
String text = "" + (int) (((float) amount / capacity) * 100);
|
||||
return amount > 0 ? Component.literal(ChatFormatting.AQUA + text + "%") : Component.literal(text + "%");
|
||||
}
|
||||
|
||||
public static Component getTimeDisplayString(double value) {
|
||||
long seconds = Math.round((value / 20));
|
||||
long minutes = Math.round(seconds / 60);
|
||||
if (seconds >= 60) {
|
||||
String appendString = (minutes == 1) ? "Minute" : "Minutes";
|
||||
String doSeconds = ((seconds - (minutes * 60)) > 0) ? ", " + (seconds - (minutes * 60)) + " Seconds" : "";
|
||||
return Component.literal(minutes + " " + appendString + doSeconds);
|
||||
} else {
|
||||
return Component.literal(seconds + " Seconds");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ARGB32 {
|
||||
public static int alpha(int pPackedColor) {
|
||||
return pPackedColor >>> 24;
|
||||
}
|
||||
|
||||
public static int red(int pPackedColor) {
|
||||
return pPackedColor >> 16 & 255;
|
||||
}
|
||||
|
||||
public static int green(int pPackedColor) {
|
||||
return pPackedColor >> 8 & 255;
|
||||
}
|
||||
|
||||
public static int blue(int pPackedColor) {
|
||||
return pPackedColor & 255;
|
||||
}
|
||||
}
|
||||
|
||||
public static int renderColorFromDye(DyeColor color) {
|
||||
return color.getMaterialColor().col | 0xFF000000;
|
||||
}
|
||||
|
||||
public static int alphaColorFromDye(DyeColor color, float alpha) {
|
||||
float[] colors = color.getTextureDiffuseColors();
|
||||
return new Color(colors[0], colors[1], colors[2], alpha).getRGB();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user