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

Dev #750

Merged
merged 10 commits into from
Aug 16, 2024
Merged

Dev #750

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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

# [2101.1.0]

### Changed
* Minecraft 1.21.1 is now required; this no longer supports Minecraft 1.21

### Added
* Sidebar buttons for this and other FTB mods can now be enabled/disabled/rearranged (new functionality in FTB Library 2101.1.0)
* A few new template substitutions are available in command rewards
* `{team_id}` - the short team name, e.g. "Dev#380df991"
* `{long_team_id}` - the full team UUID, e.g. "380df991-f603-344c-a090-369bad2a924a"
* `{member_count}` - the number of players in the team
* `{online_member_count}` - the number of currently-online players in the team

### Fixed
* Fixed "Hide Quests until Dependencies Visible" setting actually checking for dependencies being _complete_
* Added new "Hide Quests until Dependencies Complete" setting
* So there are now two independent setting for hiding quests based on dependency visibility and/or completion

# [2100.1.5]

### Changed
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id "architectury-plugin" version "3.4-SNAPSHOT"
id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
id "dev.architectury.loom" version "1.7-SNAPSHOT" apply false
id "me.modmuss50.mod-publish-plugin" version "0.5.1"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
import dev.architectury.networking.NetworkManager;
import dev.architectury.registry.client.rendering.BlockEntityRendererRegistry;
import dev.architectury.registry.client.rendering.ColorHandlerRegistry;
import dev.ftb.mods.ftblibrary.api.sidebar.ButtonOverlayRender;
import dev.ftb.mods.ftblibrary.api.sidebar.SidebarButtonCreatedEvent;
import dev.ftb.mods.ftblibrary.icon.Color4I;
import dev.ftb.mods.ftblibrary.sidebar.SidebarButtonCreatedEvent;
import dev.ftb.mods.ftblibrary.ui.CustomClickEvent;
import dev.ftb.mods.ftblibrary.ui.GuiHelper;
import dev.ftb.mods.ftbquests.api.FTBQuestsAPI;
Expand Down Expand Up @@ -117,7 +118,7 @@ private void registerItemColors(Minecraft minecraft) {

private void onSidebarButtonCreated(SidebarButtonCreatedEvent event) {
if (event.getButton().getId().equals(QUESTS_BUTTON)) {
event.getButton().setCustomTextHandler(() ->
event.getButton().addOverlayRender(ButtonOverlayRender.ofSimpleString(() ->
{
if (ClientQuestFile.exists()) {
if (ClientQuestFile.INSTANCE.isDisableGui() && !ClientQuestFile.INSTANCE.canEdit()) {
Expand All @@ -130,7 +131,7 @@ private void onSidebarButtonCreated(SidebarButtonCreatedEvent event) {
}

return "";
});
}));
}
}

Expand Down
17 changes: 14 additions & 3 deletions common/src/main/java/dev/ftb/mods/ftbquests/quest/Chapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public final class Chapter extends QuestObject {
private int defaultMinWidth = 0;
private ProgressionMode progressionMode;
private boolean hideQuestDetailsUntilStartable;
private boolean hideQuestUntilDepsComplete;
private boolean hideQuestUntilDepsVisible;
private boolean defaultRepeatable;
private Tristate consumeItems;
Expand All @@ -67,6 +68,7 @@ public Chapter(long id, BaseQuestFile file, ChapterGroup group, String filename)
defaultHideDependencyLines = false;
progressionMode = ProgressionMode.DEFAULT;
hideQuestUntilDepsVisible = false;
hideQuestUntilDepsComplete = false;
hideQuestDetailsUntilStartable = false;
defaultRepeatable = false;
consumeItems = Tristate.DEFAULT;
Expand Down Expand Up @@ -176,6 +178,7 @@ public void writeData(CompoundTag nbt, HolderLookup.Provider provider) {

if (hideQuestDetailsUntilStartable) nbt.putBoolean("hide_quest_details_until_startable", true);
if (hideQuestUntilDepsVisible) nbt.putBoolean("hide_quest_until_deps_visible", true);
if (hideQuestUntilDepsComplete) nbt.putBoolean("hide_quest_until_deps_complete", true);
if (defaultRepeatable) nbt.putBoolean("default_repeatable_quest", true);
if (requireSequentialTasks) nbt.putBoolean("require_sequential_tasks", true);

Expand Down Expand Up @@ -215,6 +218,7 @@ public void readData(CompoundTag nbt, HolderLookup.Provider provider) {
consumeItems = Tristate.read(nbt, "consume_items");
hideQuestDetailsUntilStartable = nbt.getBoolean("hide_quest_details_until_startable");
hideQuestUntilDepsVisible = nbt.getBoolean("hide_quest_until_deps_visible");
hideQuestUntilDepsComplete = nbt.getBoolean("hide_quest_until_deps_complete");
defaultRepeatable = nbt.getBoolean("default_repeatable_quest");
requireSequentialTasks = nbt.getBoolean("require_sequential_tasks");
autoFocusId = nbt.getString("autofocus_id");
Expand All @@ -234,12 +238,13 @@ public void writeNetData(RegistryFriendlyByteBuf buffer) {
flags = Bits.setFlag(flags, 0x01, alwaysInvisible);
flags = Bits.setFlag(flags, 0x02, defaultHideDependencyLines);
flags = Bits.setFlag(flags, 0x04, hideQuestDetailsUntilStartable);
flags = Bits.setFlag(flags, 0x08, hideQuestUntilDepsVisible);
flags = Bits.setFlag(flags, 0x08, hideQuestUntilDepsComplete);
flags = Bits.setFlag(flags, 0x10, defaultRepeatable);
flags = Bits.setFlag(flags, 0x20, consumeItems != Tristate.DEFAULT);
flags = Bits.setFlag(flags, 0x40, consumeItems == Tristate.TRUE);
flags = Bits.setFlag(flags, 0x80, requireSequentialTasks);
flags = Bits.setFlag(flags, 0x100, !autoFocusId.isEmpty());
flags = Bits.setFlag(flags, 0x200, hideQuestUntilDepsVisible);
buffer.writeVarInt(flags);

if (!autoFocusId.isEmpty()) buffer.writeLong(QuestObjectBase.parseHexId(autoFocusId).orElse(0L));
Expand All @@ -259,10 +264,11 @@ public void readNetData(RegistryFriendlyByteBuf buffer) {
alwaysInvisible = Bits.getFlag(flags, 0x01);
defaultHideDependencyLines = Bits.getFlag(flags, 0x02);
hideQuestDetailsUntilStartable = Bits.getFlag(flags, 0x04);
hideQuestUntilDepsVisible = Bits.getFlag(flags, 0x08);
hideQuestUntilDepsComplete = Bits.getFlag(flags, 0x08);
defaultRepeatable = Bits.getFlag(flags, 0x10);
consumeItems = Bits.getFlag(flags, 0x20) ? Bits.getFlag(flags, 0x40) ? Tristate.TRUE : Tristate.FALSE : Tristate.DEFAULT;
requireSequentialTasks = Bits.getFlag(flags, 0x80);
hideQuestUntilDepsVisible = Bits.getFlag(flags, 0x200);

autoFocusId = Bits.getFlag(flags, 0x100) ? QuestObjectBase.getCodeString(buffer.readLong()) : "";
}
Expand Down Expand Up @@ -418,6 +424,7 @@ public void fillConfigGroup(ConfigGroup config) {
visibility.addBool("default_hide_dependency_lines", defaultHideDependencyLines, v -> defaultHideDependencyLines = v, false);
visibility.addBool("hide_quest_details_until_startable", hideQuestDetailsUntilStartable, v -> hideQuestDetailsUntilStartable = v, false);
visibility.addBool("hide_quest_until_deps_visible", hideQuestUntilDepsVisible, v -> hideQuestUntilDepsVisible = v, false);
visibility.addBool("hide_quest_until_deps_complete", hideQuestUntilDepsComplete, v -> hideQuestUntilDepsComplete = v, false);

ConfigGroup misc = config.getOrCreateSubgroup("misc").setNameKey("ftbquests.quest.misc");
misc.addString("autofocus_id", autoFocusId, v -> autoFocusId = v, "", HEX_STRING);
Expand Down Expand Up @@ -490,7 +497,11 @@ public boolean hideQuestDetailsUntilStartable() {
return hideQuestDetailsUntilStartable;
}

public boolean hideQuestUntilDepsVisible() {
public boolean hideQuestUntilDepsComplete() {
return hideQuestUntilDepsComplete;
}

public boolean isHideQuestUntilDepsVisible() {
return hideQuestUntilDepsVisible;
}

Expand Down
49 changes: 39 additions & 10 deletions common/src/main/java/dev/ftb/mods/ftbquests/quest/Quest.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public final class Quest extends QuestObject implements Movable {
private Chapter chapter;
private double x, y;
private Tristate hideUntilDepsVisible;
private Tristate hideUntilDepsComplete;
private String shape;
private final List<QuestObject> dependencies;
private final List<Task> tasks;
Expand Down Expand Up @@ -92,6 +93,7 @@ public Quest(long id, Chapter chapter) {
hideDependencyLines = Tristate.DEFAULT;
hideDependentLines = false;
hideUntilDepsVisible = Tristate.DEFAULT;
hideUntilDepsComplete = Tristate.DEFAULT;
dependencyRequirement = DependencyRequirement.ALL_COMPLETED;
minRequiredDependencies = 0;
hideTextUntilComplete = Tristate.DEFAULT;
Expand Down Expand Up @@ -258,7 +260,8 @@ public void writeData(CompoundTag nbt, HolderLookup.Provider provider) {
nbt.put("dependencies", deps);
}

hideUntilDepsVisible.write(nbt, "hide");
hideUntilDepsVisible.write(nbt, "hide_until_deps_visible");
hideUntilDepsComplete.write(nbt, "hide_until_deps_complete");

if (dependencyRequirement != DependencyRequirement.ALL_COMPLETED) {
nbt.putString("dependency_requirement", dependencyRequirement.getId());
Expand Down Expand Up @@ -342,7 +345,14 @@ public void readData(CompoundTag nbt, HolderLookup.Provider provider) {
}
}

hideUntilDepsVisible = Tristate.read(nbt, "hide");
if (nbt.contains("hide", Tag.TAG_BYTE)) {
// TODO legacy; remove in 1.22
hideUntilDepsVisible = Tristate.read(nbt, "hide");
} else {
hideUntilDepsVisible = Tristate.read(nbt, "hide_until_deps_visible");
}
hideUntilDepsComplete = Tristate.read(nbt, "hide_until_deps_complete");

dependencyRequirement = DependencyRequirement.NAME_MAP.get(nbt.getString("dependency_requirement"));
hideTextUntilComplete = Tristate.read(nbt, "hide_text_until_complete");
size = nbt.getDouble("size");
Expand Down Expand Up @@ -381,6 +391,7 @@ public void writeNetData(RegistryFriendlyByteBuf buffer) {
flags = Bits.setFlag(flags, 0x20000, iconScale != 1f);
buffer.writeVarInt(flags);

hideUntilDepsComplete.write(buffer);
hideUntilDepsVisible.write(buffer);
hideDependencyLines.write(buffer);
hideTextUntilComplete.write(buffer);
Expand Down Expand Up @@ -424,6 +435,7 @@ public void writeNetData(RegistryFriendlyByteBuf buffer) {
public void readNetData(RegistryFriendlyByteBuf buffer) {
super.readNetData(buffer);
int flags = buffer.readVarInt();
hideUntilDepsComplete = Tristate.read(buffer);
hideUntilDepsVisible = Tristate.read(buffer);
hideDependencyLines = Tristate.read(buffer);
hideTextUntilComplete = Tristate.read(buffer);
Expand Down Expand Up @@ -633,7 +645,8 @@ public void onClicked(Widget clicked, MouseButton button, ConfigCallback callbac
appearance.addDouble("icon_scale", iconScale, v -> iconScale = v, 1f, 0.1, 2.0);

ConfigGroup visibility = config.getOrCreateSubgroup("visibility");
visibility.addTristate("hide", hideUntilDepsVisible, v -> hideUntilDepsVisible = v);
visibility.addTristate("hide_until_deps_complete", hideUntilDepsComplete, v -> hideUntilDepsComplete = v);
visibility.addTristate("hide_until_deps_visible", hideUntilDepsVisible, v -> hideUntilDepsVisible = v);
visibility.addBool("invisible", invisible, v -> invisible = v, false);
visibility.addInt("invisible_until_tasks", invisibleUntilTasks, v -> invisibleUntilTasks = v, 0, 0, Integer.MAX_VALUE).setCanEdit(invisible);
visibility.addTristate("hide_details_until_startable", hideDetailsUntilStartable, v -> hideDetailsUntilStartable = v);
Expand Down Expand Up @@ -715,8 +728,10 @@ public boolean isVisible(TeamData data) {
return true;
}

if (hideUntilDepsVisible.get(chapter.hideQuestUntilDepsVisible())) {
if (hideUntilDepsComplete.get(chapter.hideQuestUntilDepsComplete())) {
return data.areDependenciesComplete(this);
} else if (hideUntilDepsVisible.get(chapter.isHideQuestUntilDepsVisible())) {
return data.areDependenciesVisible(this);
}

return streamDependencies().anyMatch(object -> object.isVisible(data));
Expand Down Expand Up @@ -1016,21 +1031,35 @@ public void removeReward(Reward reward) {
rewards.remove(reward);
}

public boolean areDependenciesComplete(TeamData teamData) {
@FunctionalInterface
private interface DependencyChecker {
default boolean check(QuestObject questObject) {
return !questObject.invalid && check0(questObject);
}
boolean check0(QuestObject questObject);
}

private boolean checkDependencies(DependencyChecker checker) {
if (minRequiredDependencies > 0) {
return streamDependencies()
.filter(dep -> teamData.isCompleted(dep) && !dep.invalid)
.filter(checker::check)
.limit(minRequiredDependencies)
.count() == minRequiredDependencies;
} else if (dependencyRequirement.needOnlyOne()) {
return streamDependencies()
.anyMatch(dep -> !dep.invalid && (dependencyRequirement.needCompletion() ? teamData.isCompleted(dep) : teamData.isStarted(dep)));
return streamDependencies().anyMatch(checker::check);
} else {
return streamDependencies()
.allMatch(dep -> !dep.invalid && (dependencyRequirement.needCompletion() ? teamData.isCompleted(dep) : teamData.isStarted(dep)));
return streamDependencies().allMatch(checker::check);
}
}

public boolean areDependenciesComplete(TeamData teamData) {
return checkDependencies(dep -> dependencyRequirement.needCompletion() ? teamData.isCompleted(dep) : teamData.isStarted(dep));
}

public boolean areDependenciesVisible(TeamData teamData) {
return checkDependencies(dep -> dep.isVisible(teamData));
}

public List<Pair<Integer,Integer>> buildDescriptionIndex() {
List<Pair<Integer,Integer>> index = new ArrayList<>();

Expand Down
43 changes: 23 additions & 20 deletions common/src/main/java/dev/ftb/mods/ftbquests/quest/TeamData.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.apache.commons.lang3.function.ToBooleanBiFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -77,8 +78,9 @@ public void encode(FriendlyByteBuf buf, TeamData data) {
private final Long2LongOpenHashMap completed;
private final Object2ObjectOpenHashMap<UUID,PerPlayerData> perPlayerData;

private Long2ByteOpenHashMap areDependenciesCompleteCache;
private Object2ByteOpenHashMap<QuestKey> unclaimedRewardsCache;
private final Long2ByteOpenHashMap areDependenciesCompleteCache;
private final Long2ByteOpenHashMap areDependenciesVisibleCache;
private final Object2ByteOpenHashMap<QuestKey> unclaimedRewardsCache;

public TeamData(UUID teamId, BaseQuestFile file) {
this(teamId, file, "");
Expand All @@ -100,6 +102,9 @@ public TeamData(UUID teamId, BaseQuestFile file, String name) {
completed = new Long2LongOpenHashMap();
completed.defaultReturnValue(0L);
perPlayerData = new Object2ObjectOpenHashMap<>();
areDependenciesCompleteCache = new Long2ByteOpenHashMap();
areDependenciesVisibleCache = new Long2ByteOpenHashMap();
unclaimedRewardsCache = new Object2ByteOpenHashMap<>();
}

public UUID getTeamId() {
Expand Down Expand Up @@ -257,14 +262,8 @@ public boolean isRewardClaimed(UUID player, Reward reward) {
}

public boolean hasUnclaimedRewards(UUID player, QuestObject object) {
if (unclaimedRewardsCache == null) {
unclaimedRewardsCache = new Object2ByteOpenHashMap<>();
unclaimedRewardsCache.defaultReturnValue(BOOL_UNKNOWN);
}

QuestKey key = QuestKey.create(player, object.id);
byte b = unclaimedRewardsCache.getByte(key);

byte b = unclaimedRewardsCache.getOrDefault(key, BOOL_UNKNOWN);
if (b == BOOL_UNKNOWN) {
b = object.hasUnclaimedRewardsRaw(this, player) ? BOOL_TRUE : BOOL_FALSE;
unclaimedRewardsCache.put(key, b);
Expand Down Expand Up @@ -320,8 +319,9 @@ public boolean resetReward(UUID player, Reward reward) {
}

public void clearCachedProgress() {
areDependenciesCompleteCache = null;
unclaimedRewardsCache = null;
areDependenciesCompleteCache.clear();
areDependenciesVisibleCache.clear();
unclaimedRewardsCache.clear();
}

public SNBTCompoundTag serializeNBT() {
Expand Down Expand Up @@ -524,25 +524,28 @@ public boolean isCompleted(QuestObject object) {
return completed.containsKey(object.id);
}

public boolean areDependenciesComplete(Quest quest) {
private boolean checkDepsCached(Quest quest, Long2ByteOpenHashMap cache, ToBooleanBiFunction<Quest,TeamData> checker) {
if (!quest.hasDependencies()) {
return true;
}

if (areDependenciesCompleteCache == null) {
areDependenciesCompleteCache = new Long2ByteOpenHashMap();
areDependenciesCompleteCache.defaultReturnValue(BOOL_UNKNOWN);
}

byte res = areDependenciesCompleteCache.get(quest.id);
byte res = cache.getOrDefault(quest.id, BOOL_UNKNOWN);
if (res == BOOL_UNKNOWN) {
res = quest.areDependenciesComplete(this) ? BOOL_TRUE : BOOL_FALSE;
areDependenciesCompleteCache.put(quest.id, res);
res = checker.applyAsBoolean(quest, this) ? BOOL_TRUE : BOOL_FALSE;
cache.put(quest.id, res);
}

return res == BOOL_TRUE;
}

public boolean areDependenciesComplete(Quest quest) {
return checkDepsCached(quest, areDependenciesCompleteCache, Quest::areDependenciesComplete);
}

public boolean areDependenciesVisible(Quest quest) {
return checkDepsCached(quest, areDependenciesVisibleCache, Quest::areDependenciesVisible);
}

public boolean canStartTasks(Quest quest) {
return quest.getProgressionMode() == ProgressionMode.FLEXIBLE || areDependenciesComplete(quest);
}
Expand Down
Loading
Loading