8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ authors=ModFest
contributors=Prospector, Sisby folk, acikek, afamiliarquiet
license=MIT
# Mod Version
baseVersion=0.6.4
baseVersion=0.7.0
# Branch Metadata
branch=1.21
tagBranch=1.21
compatibleVersions=1.21, 1.21.1
branch=1.21.7
tagBranch=1.21.7
compatibleVersions=1.21.7
compatibleLoaders=fabric, quilt, neoforge
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
14 changes: 7 additions & 7 deletions libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[versions]
loom = "1.7.+"
loom = "1.11.+"
minotaur = "2.+"

kaleidoConfig = "0.3.1+1.3.1"

mc = "1.21.1"
fl = "0.16.7"
yarn = "1.21.1+build.3"
fapi = "0.104.0+1.21.1"
mc = "1.21.7"
fl = "0.16.14"
yarn = "1.21.7+build.4"
fapi = "0.128.2+1.21.7"

spruceui = "5.1.0+1.21"
modmenu = "11.0.3"
spruceui = "8.0.0+1.21.6"
modmenu = "15.0.0-beta.3"

[plugins]
loom = { id = "fabric-loom", version.ref = "loom" }
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/net/modfest/ballotbox/BallotBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public class BallotBox implements ModInitializer {
public static final String ID = "ballotbox";
public static final Logger LOGGER = LoggerFactory.getLogger(ID);
public static final BallotBoxConfig CONFIG = BallotBoxConfig.createToml(FabricLoader.getInstance().getConfigDir(), "", ID, BallotBoxConfig.class);
public static final String STATE_KEY = "ballotbox_ballots";
public static BallotState STATE = null;
public static Instant closingTime = null;

Expand Down Expand Up @@ -66,7 +65,7 @@ public void onInitialize() {
CommandRegistrationCallback.EVENT.register(BallotBoxCommands::register);
ServerWorldEvents.LOAD.register(((server, world) -> {
if (world.getRegistryKey() == World.OVERWORLD) {
STATE = world.getPersistentStateManager().getOrCreate(BallotState.getPersistentStateType(), STATE_KEY);
STATE = world.getPersistentStateManager().getOrCreate(BallotState.TYPE);
}
}));
ServerLifecycleEvents.SERVER_STARTED.register((server -> {
Expand All @@ -86,4 +85,4 @@ public void onInitialize() {
}));
LOGGER.info("[BallotBox] Initialized!");
}
}
}
23 changes: 7 additions & 16 deletions src/main/java/net/modfest/ballotbox/BallotState.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,33 @@

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtOps;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.Uuids;
import net.minecraft.world.PersistentState;
import net.minecraft.world.PersistentStateType;
import net.modfest.ballotbox.data.VotingSelections;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class BallotState extends PersistentState {
private static final String STATE_KEY = "ballotbox_ballots";

public static final Codec<BallotState> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.unboundedMap(Uuids.CODEC, VotingSelections.CODEC).xmap(s -> (Map<UUID, VotingSelections>) new ConcurrentHashMap<>(s), ConcurrentHashMap::new).fieldOf("selections").forGetter(BallotState::selections)
).apply(instance, BallotState::new));

public static PersistentState.Type<BallotState> getPersistentStateType() {
return new PersistentState.Type<>(() -> new BallotState(new ConcurrentHashMap<>()), BallotState::fromNbt, null);
}
public static final PersistentStateType<BallotState> TYPE = new PersistentStateType<>(STATE_KEY,
() -> new BallotState(new ConcurrentHashMap<>()),
BallotState.CODEC,
null);

private final Map<UUID, VotingSelections> selections;

private BallotState(Map<UUID, VotingSelections> selections) {
this.selections = selections;
}

private static BallotState fromNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
return BallotState.CODEC.decode(NbtOps.INSTANCE, nbt.getCompound("data")).getOrThrow().getFirst();
}

@Override
public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
nbt.put("data", BallotState.CODEC.encodeStart(NbtOps.INSTANCE, this).getOrThrow());
return nbt;
}

public Map<UUID, VotingSelections> selections() {
return selections;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ConfirmLinkScreen;
import net.minecraft.client.gui.screen.CreditsScreen;
import net.minecraft.client.gui.screen.GameMenuScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.gui.widget.Widget;
import net.minecraft.client.sound.MusicInstance;
import net.minecraft.sound.MusicType;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
Expand Down Expand Up @@ -38,7 +38,7 @@ public static List<Pair<BallotBoxConfig.ButtonSettings, Function<Screen, ButtonW
list.add(new Pair<>(BallotBox.CONFIG.credits_button, (screen) -> ButtonWidget.builder(Text.of(BallotBox.CONFIG.credits_text.value()), b -> {
MinecraftClient.getInstance().setScreen(new CreditsScreen(false, () -> MinecraftClient.getInstance().setScreen(screen)));
MinecraftClient.getInstance().getMusicTracker().stop();
MinecraftClient.getInstance().getMusicTracker().play(MusicType.CREDITS);
MinecraftClient.getInstance().getMusicTracker().play(new MusicInstance(MusicType.CREDITS));
})));

return list;
Expand Down
79 changes: 42 additions & 37 deletions src/main/java/net/modfest/ballotbox/client/VotingScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.mojang.blaze3d.systems.RenderSystem;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.background.EmptyBackground;
import dev.lambdaurora.spruceui.render.SpruceGuiGraphics;
import dev.lambdaurora.spruceui.screen.SpruceScreen;
import dev.lambdaurora.spruceui.tooltip.TooltipData;
import dev.lambdaurora.spruceui.widget.SpruceButtonWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceContainerWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceOptionListWidget;
Expand All @@ -15,6 +16,7 @@
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.RenderPipelines;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.texture.NativeImageBackedTexture;
import net.minecraft.client.texture.Sprite;
Expand All @@ -31,6 +33,7 @@
import net.modfest.ballotbox.packet.C2SUpdateVote;
import net.modfest.ballotbox.packet.S2CVoteScreenData;
import net.modfest.ballotbox.util.ModMetaUtil;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;

import java.util.ArrayList;
Expand Down Expand Up @@ -96,10 +99,12 @@ protected void initSidePanel() {
Map<String, List<VotingCategory>> typedCategories = categories.stream().collect(Collectors.groupingBy(VotingCategory::type));
typedCategories.entrySet().stream().sorted(Comparator.comparing(e -> CATEGORY_TYPES.contains(e.getKey()) ? CATEGORY_TYPES.indexOf(e.getKey()) : 99)).forEach(e -> {
e.getValue().forEach(category -> addCategoryTab(tabs, category));
if (tabs.getList().children().size() < categories.size() + typedCategories.size() - 1) tabs.addSeparatorEntry(null);
if (tabs.getList().children().size() < categories.size() + typedCategories.size() - 1) {
tabs.addSeparatorEntry(null);
}
});
tabs.getList().setBackground(EmptyBackground.EMPTY_BACKGROUND);
addSelectableChild(tabs);
addDrawableChild(tabs);
}

@Override
Expand All @@ -112,24 +117,21 @@ public void renderBackground(DrawContext context, int mouseX, int mouseY, float

public void renderLockup(DrawContext context) {
if (lockupSprite == null) return;
RenderSystem.enableBlend();
int texHeight = lockupSprite.getContents().getHeight();
int texWidth = lockupSprite.getContents().getWidth();
int drawHeight = sidePanelWidth * texHeight / texWidth;
context.drawGuiTexture(LOCKUP_TEXTURE, 0, (sidePanelVerticalPadding - drawHeight) / 2, sidePanelWidth, drawHeight);
RenderSystem.disableBlend();
context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, LOCKUP_TEXTURE, 0, (sidePanelVerticalPadding - drawHeight) / 2, sidePanelWidth, drawHeight);
}

@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
renderBackground(context, mouseX, mouseY, delta);
public void render(@NotNull SpruceGuiGraphics graphics, int mouseX, int mouseY, float delta) {
if (loaded) {
super.render(context, mouseX, mouseY, delta);
renderLockup(context);
context.drawVerticalLine(sidePanelWidth, 0, height, 0xFFFFFFFF);
super.render(graphics, mouseX, mouseY, delta);
renderLockup(graphics.vanilla());
graphics.vanilla().drawVerticalLine(sidePanelWidth, 0, height, 0xFFFFFFFF);
} else {
int textWidth = textRenderer.getWidth(LOADING_INDICATOR);
context.drawText(textRenderer, LOADING_INDICATOR, width - textWidth - 10, height - 15, 0xFFFFFFFF, true);
graphics.drawText(textRenderer, LOADING_INDICATOR, width - textWidth - 10, height - 15, 0xFFFFFFFF, true);
}
}

Expand Down Expand Up @@ -198,14 +200,17 @@ public VotingOptionButtonWidget(Position position, int width, int height, Voting
setTooltip(url == null ? Text.literal(option.description()).formatted(Formatting.GRAY) : Text.literal(option.description()).formatted(Formatting.GRAY).append(Text.literal("\n")).append(Text.literal("Right-Click").formatted(Formatting.GOLD)).append(Text.literal(" to open the mod page.").formatted(Formatting.WHITE)));
}

@Override
public boolean isActive() {
return !prohibited && super.isActive();
return !prohibited && active;
}

@Override
public Optional<Text> getTooltip() {
return isActive() ? super.getTooltip() : prohibited ? Optional.of(Text.literal("Prohibited by another category!").formatted(Formatting.GRAY)) : Optional.of(Text.literal("You've reached the category vote limit!").formatted(Formatting.GRAY));
public @NotNull TooltipData getTooltip() {
return isActive()
? super.getTooltip()
: prohibited
? TooltipData.builder().text(Text.literal("Prohibited by another category!").formatted(Formatting.GRAY)).build()
: TooltipData.builder().text(Text.literal("You've reached the category vote limit!").formatted(Formatting.GRAY)).build();
}

@Override
Expand All @@ -226,41 +231,41 @@ protected Identifier getTexture() {
}

@Override
protected void renderButton(DrawContext context, int mouseX, int mouseY, float delta) {
protected void renderButton(SpruceGuiGraphics graphics, int mouseX, int mouseY, float delta) {
int textWidth = client.textRenderer.getWidth(getMessage());
int left = getX() + 2, right = getX() + getWidth() - 2;
int bottom = getY() + getHeight();
int textY = (getY() * 2 + getHeight() - 9) / 2 + 1;
if (texture != null) {
context.drawTexture(texture, left, getY() + 2, 16, 16, 0, 0, 16, 16, 16, 16);
graphics.vanilla().drawTexture(RenderPipelines.GUI_TEXTURED, texture, left, getY() + 2, 16, 16, 0, 0, 16, 16, 16, 16);
}
if (textWidth <= getWidth()) {
context.drawCenteredTextWithShadow(client.textRenderer, getMessage(), left + getWidth() / 2, textY, 0xFFFFFFFF);
graphics.vanilla().drawCenteredTextWithShadow(client.textRenderer, getMessage(), left + getWidth() / 2, textY, 0xFFFFFFFF);
return;
}
int extraWidth = textWidth - getWidth();
double seconds = (double) Util.getMeasuringTimeMs() / 1000.0;
double clampedWidth = Math.max(extraWidth * 0.5, 3.0);
double scroll = Math.sin((Math.PI / 2.0) * Math.cos((Math.PI * 2) * seconds / clampedWidth)) / 2.0 + 0.5;
double offset = MathHelper.lerp(scroll, 0.0, extraWidth);
context.enableScissor(left, Math.max(getY(), parent.getY()), right, bottom);
context.drawTextWithShadow(client.textRenderer, getMessage(), left - (int) offset, textY, 0xFFFFFFFF);
context.disableScissor();
graphics.enableScissor(left, Math.max(getY(), parent.getY()), right, bottom);
graphics.vanilla().drawTextWithShadow(client.textRenderer, getMessage(), left - (int) offset, textY, 0xFFFFFFFF);
graphics.disableScissor();
}

@Override
protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
super.renderWidget(context, mouseX, mouseY, delta);
protected void renderWidget(SpruceGuiGraphics graphics, int mouseX, int mouseY, float delta) {
super.renderWidget(graphics, mouseX, mouseY, delta);
if (selected) {
context.drawTexture(CHECKMARK_TEXTURE, getX() + getWidth() - 11, getY() + getHeight() - 9, 0, 0, 7, 6, 7, 6);
graphics.drawTexture(RenderPipelines.GUI_TEXTURED, CHECKMARK_TEXTURE, getX() + getWidth() - 11, getY() + getHeight() - 9, 0, 0, 7, 6, 7, 6);
}
}

@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
context.enableScissor(parent.getX(), parent.getY(), parent.getX() + parent.getWidth(), parent.getY() + parent.getHeight());
super.render(context, mouseX, mouseY, delta);
context.disableScissor();
public void render(@NotNull SpruceGuiGraphics graphics, int mouseX, int mouseY, float delta) {
graphics.enableScissor(parent.getX(), parent.getY(), parent.getX() + parent.getWidth(), parent.getY() + parent.getHeight());
super.render(graphics, mouseX, mouseY, delta);
graphics.disableScissor();
}
}

Expand Down Expand Up @@ -319,19 +324,19 @@ public void updateProhibitions(String optionId, boolean selected) {
public float drawTitleText(DrawContext context) {
int titleWidth = client.textRenderer.getWidth(titleText);
float titleScale = Math.min((float) (width - 20) / titleWidth, 2.0f);
context.getMatrices().push();
context.getMatrices().translate(getPosition().getX() + 10, 10, 0);
context.getMatrices().scale(titleScale, titleScale, 1.0f);
context.getMatrices().pushMatrix();
context.getMatrices().translate(getPosition().getX() + 10, 10);
context.getMatrices().scale(titleScale, titleScale);
context.drawText(client.textRenderer, titleText, 0, 0, 0xFFFFFFFF, true);
context.getMatrices().pop();
context.getMatrices().popMatrix();
return titleScale;
}

@Override
protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
float titleScale = drawTitleText(context);
context.drawText(client.textRenderer, Text.literal(category.description()), getPosition().getX() + 10, 15 + (int) (9 * titleScale), 0xFFFFFFFF, true);
super.renderWidget(context, mouseX, mouseY, delta);
protected void renderWidget(SpruceGuiGraphics graphics, int mouseX, int mouseY, float delta) {
float titleScale = drawTitleText(graphics.vanilla());
graphics.drawText(client.textRenderer, Text.literal(category.description()), getPosition().getX() + 10, 15 + (int) (9 * titleScale), 0xFFFFFFFF, true);
super.renderWidget(graphics, mouseX, mouseY, delta);
}
}
}
13 changes: 11 additions & 2 deletions src/main/java/net/modfest/ballotbox/util/ModMetaUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
* Liberally stolen from ModMenu. Thanks ModMenu!
Expand All @@ -23,7 +24,15 @@ public class ModMetaUtil {

public static NativeImageBackedTexture createIcon(ModContainer iconSource, String iconPath) {
try {
Path path = iconSource.getPath(iconPath);
Optional<Path> optionalPath = iconSource.findPath(iconPath);

if(optionalPath.isEmpty()) {
BallotBox.LOGGER.warn("Missing icon for source {}", iconSource);
return null;
}

Path path = optionalPath.get();

NativeImageBackedTexture cachedIcon = modIconCache.get(path);
if (cachedIcon != null) {
return cachedIcon;
Expand All @@ -35,7 +44,7 @@ public static NativeImageBackedTexture createIcon(ModContainer iconSource, Strin
try (InputStream inputStream = Files.newInputStream(path)) {
NativeImage image = NativeImage.read(Objects.requireNonNull(inputStream));
Validate.validState(image.getHeight() == image.getWidth(), "Must be square icon");
NativeImageBackedTexture tex = new NativeImageBackedTexture(image);
NativeImageBackedTexture tex = new NativeImageBackedTexture(() -> iconPath, image);
modIconCache.put(path, tex);
return tex;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/ballotbox.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
},
"mixins": [
"client.ElementAccessor"
]
]
}