Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow using different modes for each entity #31

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/main/java/io/ix0rai/rainglow/Rainglow.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ public static Identifier id(String id) {
return new Identifier(MOD_ID, id);
}

public static String generateRandomColourId(World world, RandomGenerator random) {
var colours = MODE_CONFIG.getMode(world).getColours();
public static String generateRandomColourId(World world, RandomGenerator random, RainglowEntity entity) {
var colours = MODE_CONFIG.getMode(world, entity).getColours();
return colours.get(random.nextInt(colours.size())).getId();
}

public static boolean colourUnloaded(World world, RainglowEntity entityType, String colour) {
var colours = MODE_CONFIG.getMode(world).getColours();
var colours = MODE_CONFIG.getMode(world, entityType).getColours();
return !colours.contains(RainglowColour.get(colour)) && !colour.equals(entityType.getDefaultColour().getId());
}

Expand All @@ -85,7 +85,7 @@ public static RainglowColour getColour(World world, RainglowEntity entityType, D
String colour = tracker.get(entityType.getTrackedData());
if (colourUnloaded(world, entityType, colour)) {
// Use last generated colour if not null else generate a new colour
tracker.set(entityType.getTrackedData(), generateRandomColourId(world, random));
tracker.set(entityType.getTrackedData(), generateRandomColourId(world, random, entityType));
colour = tracker.get(entityType.getTrackedData());
}

Expand Down
112 changes: 112 additions & 0 deletions src/main/java/io/ix0rai/rainglow/config/ModeConfigScreen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package io.ix0rai.rainglow.config;

import io.ix0rai.rainglow.Rainglow;
import io.ix0rai.rainglow.data.RainglowEntity;
import io.ix0rai.rainglow.data.RainglowMode;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.option.GameOptionsScreen;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.gui.widget.button.ButtonWidget;
import net.minecraft.client.gui.widget.button.CyclingButtonWidget;
import net.minecraft.client.gui.widget.layout.HeaderFooterLayoutWidget;
import net.minecraft.client.gui.widget.layout.LinearLayoutWidget;
import net.minecraft.client.gui.widget.list.ButtonListWidget;
import net.minecraft.client.gui.widget.text.TextWidget;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.client.toast.Toast;
import net.minecraft.text.CommonTexts;
import net.minecraft.text.Text;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ModeConfigScreen extends GameOptionsScreen implements ScreenWithUnsavedWarning {
private final ButtonWidget saveButton;
private final Map<RainglowEntity, RainglowMode> updatedModes = new HashMap<>();
private boolean isConfirming;

private static final Text TITLE = Rainglow.translatableText("config.custom");

public ModeConfigScreen(Screen parent) {
super(parent, MinecraftClient.getInstance().options, TITLE);
this.saveButton = ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> this.save()).build();
this.saveButton.active = false;
}

private ClickableWidget createEntityCyclingWidget(RainglowEntity entity) {
Text text = Text.translatable("entity.minecraft." + entity.getId());

return CyclingButtonWidget.builder(RainglowMode::getText)
.values(RainglowMode.values())
// todo this will crash if the world is null
.initially(Rainglow.MODE_CONFIG.getMode(MinecraftClient.getInstance().world, entity))
.tooltip(RainglowConfigScreen::createColourListLabel)
.build(
text,
(cyclingButtonWidget, mode) -> {
this.saveButton.active = true;
this.updatedModes.put(entity, mode);
}
);
}

private void save() {
for (Map.Entry<RainglowEntity, RainglowMode> entry : this.updatedModes.entrySet()) {
Rainglow.MODE_CONFIG.setMode(MinecraftClient.getInstance().world, entry.getValue(), entry.getKey());
}

Rainglow.CONFIG.save();
this.saveButton.active = false;
}

@Override
public void init() {
HeaderFooterLayoutWidget headerFooterWidget = new HeaderFooterLayoutWidget(this, 61, 33);
headerFooterWidget.addToHeader(new TextWidget(TITLE, this.textRenderer), settings -> settings.alignHorizontallyCenter().setBottomPadding(28));

if (!this.isConfirming) {
ButtonListWidget buttonListWidget = headerFooterWidget.addToContents(new ButtonListWidget(this.client, this.width, this.height, this));
for (RainglowEntity entity : RainglowEntity.values()) {
buttonListWidget.method_58227(List.of(this.createEntityCyclingWidget(entity)));
}

LinearLayoutWidget linearLayout = headerFooterWidget.addToFooter(LinearLayoutWidget.createHorizontal().setSpacing(8));
linearLayout.add(ButtonWidget.builder(CommonTexts.DONE, button -> this.closeScreen()).build());
linearLayout.add(this.saveButton);
} else {
this.setUpUnsavedWarning(headerFooterWidget, this.textRenderer, this.parent);
}

headerFooterWidget.visitWidgets(this::addDrawableSelectableElement);
headerFooterWidget.arrangeElements();
}

private static void sendNoColoursToast() {
Toast toast = new SystemToast(SystemToast.Id.PACK_LOAD_FAILURE, Rainglow.translatableText("config.no_custom_colours"), Rainglow.translatableText("config.no_custom_colours_description"));
MinecraftClient.getInstance().getToastManager().add(toast);
}

@Override
public void setConfirming(boolean confirming) {
this.isConfirming = confirming;
}

@Override
public void clearAndInit() {
super.clearAndInit();
}

@Override
public void closeScreen() {
if (this.saveButton.active) {
this.isConfirming = true;
this.clearAndInit();
} else {
MinecraftClient.getInstance().setScreen(this.parent);
}
}
}

120 changes: 102 additions & 18 deletions src/main/java/io/ix0rai/rainglow/config/PerWorldConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,91 @@
import folk.sisby.kaleido.lib.quiltconfig.api.values.TrackedValue;
import folk.sisby.kaleido.lib.quiltconfig.api.values.ValueMap;
import io.ix0rai.rainglow.Rainglow;
import io.ix0rai.rainglow.data.RainglowEntity;
import io.ix0rai.rainglow.data.RainglowMode;
import io.ix0rai.rainglow.mixin.MinecraftServerAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

@SerializedNameConvention(NamingSchemes.SNAKE_CASE)
public class PerWorldConfig extends ReflectiveConfig {
@Comment("The mode used for each non-local world.")
@Comment("Note that for singleplayer worlds, the mode is saved in the world folder in the file \"config/rainglow.json\".")
public final TrackedValue<ValueMap<String>> modesByWorld = this.map("").build();
public final TrackedValue<ValueMap<ValueMap<String>>> modesByWorld = this.map(ValueMap.builder("").build()).build();

public RainglowMode getMode(World world) {
// todo hot garbage
public Map<RainglowEntity, RainglowMode> getModes(World world) {
var saveName = getSaveName(world);
Either<Map<String, String>, ValueMap<String>> modes = null;

if (saveName.right().isPresent()) {
modes = Either.right(modesByWorld.value().get(saveName.right().get()));
} else if (saveName.left().isPresent()) {
Path path = getJsonPath(saveName.left().get());
if (Files.exists(path)) {
try {
var data = readJson(path);
modes = Either.left(data.entities);
} catch (Exception e) {
Rainglow.LOGGER.error("Failed to load Rainglow config for world " + saveName.left().get(), e);
}
} else {
save(saveName.left().get(), RainglowMode.get(Rainglow.CONFIG.defaultMode.value()), null);
}
}

if (modes == null) {
var map = new HashMap<RainglowEntity, RainglowMode>();
for (RainglowEntity entity : RainglowEntity.values()) {
map.put(entity, RainglowMode.get(Rainglow.CONFIG.defaultMode.value()));
}

return map;
} else {
if (modes.left().isPresent()) {
var map = new HashMap<RainglowEntity, RainglowMode>();
for (RainglowEntity entity : RainglowEntity.values()) {
map.put(entity, RainglowMode.get(modes.left().get().get(entity.getId())));
}

return map;
} else {
var map = new HashMap<RainglowEntity, RainglowMode>();
for (RainglowEntity entity : RainglowEntity.values()) {
map.put(entity, RainglowMode.get(modes.right().get().get(entity.getId())));
}

return map;
}
}
}

public RainglowMode getMode(World world, RainglowEntity entity) {
var saveName = getSaveName(world);
String mode = null;

if (saveName.right().isPresent()) {
mode = modesByWorld.value().get(saveName.right().get());
mode = modesByWorld.value().get(entity.getId()).get(saveName.right().get());
} else if (saveName.left().isPresent()) {
Path path = getJsonPath(saveName.left().get());
if (Files.exists(path)) {
try {
var data = Rainglow.GSON.fromJson(Files.readString(path), RainglowJson.class);
if (data != null) {
mode = data.mode;
}
var data = readJson(path);
mode = data.entities.get(entity.getId());
} catch (Exception e) {
Rainglow.LOGGER.error("Failed to load Rainglow config for world " + saveName.left().get(), e);
}
} else {
save(saveName.left().get(), RainglowMode.get(Rainglow.CONFIG.defaultMode.value()));
save(saveName.left().get(), RainglowMode.get(Rainglow.CONFIG.defaultMode.value()), entity);
}
}

Expand All @@ -53,18 +103,47 @@ public RainglowMode getMode(World world) {
}
}

public void setMode(World world, RainglowMode mode) {
var saveName = getSaveName(world);
if (saveName.right().isPresent()) {
modesByWorld.value().put(saveName.right().get(), mode.getId());
} else if (saveName.left().isPresent()) {
save(saveName.left().get(), mode);
private static RainglowJson readJson(Path path) {
if (Files.exists(path)) {
try {
return Rainglow.GSON.fromJson(Files.readString(path), RainglowJson.class);
} catch (Exception e) {
Rainglow.LOGGER.error("Failed to load Rainglow config for world " + path, e);
}
}

return new RainglowJson(RainglowMode.get(Rainglow.CONFIG.defaultMode.value()));
}

public void setMode(World world, RainglowMode mode, @Nullable RainglowEntity entity) {
Consumer<String> setter = (id) -> {
var saveName = getSaveName(world);
if (saveName.right().isPresent()) {
modesByWorld.value().get(id).put(saveName.right().get(), mode.getId());
} else if (saveName.left().isPresent()) {
save(saveName.left().get(), mode, entity);
}
};

if (entity != null) {
setter.accept(entity.getId());
} else {
for (RainglowEntity e : RainglowEntity.values()) {
setter.accept(e.getId());
}
}
}

private static void save(Path worldPath, RainglowMode mode) {
private static void save(Path worldPath, RainglowMode mode, @Nullable RainglowEntity entity) {
Path path = getJsonPath(worldPath);
var data = new RainglowJson(mode.getId());
RainglowJson data;

if (Files.exists(path) && entity != null) {
data = readJson(path);
data.entities.put(entity.getId(), mode.getId());
} else {
data = new RainglowJson(mode);
}

try {
Path configPath = getConfigFolderPath(worldPath);
Expand Down Expand Up @@ -108,7 +187,12 @@ private static Path getWorldPath(MinecraftServer server) {
return ((MinecraftServerAccessor) server).getSession().method_54543().path();
}

private record RainglowJson(String mode) {

private record RainglowJson(Map<String, String> entities) {
public RainglowJson(RainglowMode mode) {
this(new HashMap<>());
for (RainglowEntity entity : RainglowEntity.values()) {
this.entities.put(entity.getId(), mode.getId());
}
}
}
}
Loading
Loading