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

Banner Merge Adapter #204

Merged
merged 1 commit into from Jan 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -109,6 +109,7 @@
import me.wolfyscript.customcrafting.recipes.items.extension.ResultExtensionAdvancement;
import me.wolfyscript.customcrafting.recipes.items.extension.SoundResultExtension;
import me.wolfyscript.customcrafting.recipes.items.target.MergeAdapter;
import me.wolfyscript.customcrafting.recipes.items.target.adapters.BannerMergeAdapter;
import me.wolfyscript.customcrafting.recipes.items.target.adapters.BookMetaMergeAdapter;
import me.wolfyscript.customcrafting.recipes.items.target.adapters.DamageMergeAdapter;
import me.wolfyscript.customcrafting.recipes.items.target.adapters.DisplayLoreMergeAdapter;
Expand Down Expand Up @@ -284,6 +285,7 @@ public void onLoad() {
}
if (ServerVersion.getWUVersion().isAfterOrEq(WUVersion.of(4, 16, 9, 6))) {
resultMergeAdapters.register(new BookMetaMergeAdapter());
resultMergeAdapters.register(new BannerMergeAdapter());
}

getLogger().info("Registering Recipe Conditions");
Expand Down
@@ -0,0 +1,190 @@
/*
* ____ _ _ ____ ___ ____ _ _ ____ ____ ____ ____ ___ _ _ _ ____
* | | | [__ | | | |\/| | |__/ |__| |___ | | |\ | | __
* |___ |__| ___] | |__| | | |___ | \ | | | | | | \| |__]
*
* CustomCrafting Recipe creation and management tool for Minecraft
* Copyright (C) 2021 WolfyScript
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package me.wolfyscript.customcrafting.recipes.items.target.adapters;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import me.wolfyscript.customcrafting.recipes.data.IngredientData;
import me.wolfyscript.customcrafting.recipes.data.RecipeData;
import me.wolfyscript.customcrafting.recipes.items.target.MergeAdapter;
import me.wolfyscript.customcrafting.utils.NamespacedKeyUtils;
import me.wolfyscript.lib.com.fasterxml.jackson.annotation.JsonCreator;
import me.wolfyscript.lib.com.fasterxml.jackson.annotation.JsonProperty;
import me.wolfyscript.utilities.api.inventory.custom_items.CustomItem;
import me.wolfyscript.utilities.util.NamespacedKey;
import me.wolfyscript.utilities.util.eval.context.EvalContext;
import me.wolfyscript.utilities.util.eval.context.EvalContextPlayer;
import me.wolfyscript.utilities.util.eval.operators.BoolOperator;
import me.wolfyscript.utilities.util.eval.operators.BoolOperatorConst;
import me.wolfyscript.utilities.util.eval.value_providers.ValueProvider;
import org.bukkit.DyeColor;
import org.bukkit.block.Block;
import org.bukkit.block.banner.Pattern;
import org.bukkit.block.banner.PatternType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BannerMeta;
import org.jetbrains.annotations.Nullable;

public class BannerMergeAdapter extends MergeAdapter {

private BoolOperator replacePattern = new BoolOperatorConst(false);
private ValueProvider<Integer> insertAtIndex = null;
private List<ElementOptionBannerPattern> patterns;
private List<PatternOption> extra;
private BoolOperator addExtraFirst;

public BannerMergeAdapter() {
super(new NamespacedKey(NamespacedKeyUtils.NAMESPACE, "banner"));
}

public BannerMergeAdapter(BannerMergeAdapter adapter) {
super(adapter);
}

public Optional<ValueProvider<Integer>> insertAtIndex() {
return Optional.ofNullable(insertAtIndex);
}

public void setInsertAtIndex(ValueProvider<Integer> insertAtIndex) {
this.insertAtIndex = insertAtIndex;
}

public ValueProvider<Integer> getInsertAtIndex() {
return insertAtIndex;
}

public BoolOperator getReplacePattern() {
return replacePattern;
}

public void setReplacePattern(BoolOperator replacePattern) {
this.replacePattern = replacePattern;
}

public List<ElementOptionBannerPattern> getPatterns() {
return patterns;
}

public void setPatterns(List<ElementOptionBannerPattern> patterns) {
this.patterns = patterns;
}

public List<PatternOption> getExtra() {
return extra;
}

public void setExtra(List<PatternOption> extra) {
this.extra = extra;
}

public BoolOperator getAddExtraFirst() {
return addExtraFirst;
}

public void setAddExtraFirst(BoolOperator addExtraFirst) {
this.addExtraFirst = addExtraFirst;
}

private List<Pattern> extra(EvalContext evalContext) {
return extra.stream().map(patternOption -> new Pattern(patternOption.dyeColor, patternOption.type)).toList();
}

@Override
public ItemStack merge(RecipeData<?> recipeData, @Nullable Player player, @Nullable Block block, CustomItem customResult, ItemStack result) {
var resultMeta = result.getItemMeta();
if (!(resultMeta instanceof BannerMeta bannerResultMeta)) return result;
var evalContext = player == null ? new EvalContext() : new EvalContextPlayer(player);
List<Pattern> finalPatterns = new ArrayList<>();
for (IngredientData data : recipeData.getBySlots(slots)) {
var meta = data.itemStack().getItemMeta();
if (!(meta instanceof BannerMeta bannerMeta)) continue;
List<Pattern> targetPatterns = bannerMeta.getPatterns();
for (ElementOptionBannerPattern line : patterns) {
finalPatterns.addAll(line.readFromSource(targetPatterns, evalContext));
}
}
List<Pattern> resultPatterns = new ArrayList<>(bannerResultMeta.getPatterns());
if (replacePattern.evaluate(evalContext)) {
resultPatterns = addExtraFirst.evaluate(evalContext) ? extra(evalContext) : new ArrayList<>();
resultPatterns.addAll(finalPatterns);
} else {
if (addExtraFirst.evaluate(evalContext)) {
resultPatterns.addAll(extra(evalContext));
}
int index = insertAtIndex().map(integerValueProvider -> integerValueProvider.getValue(evalContext)).orElse(resultPatterns.size());
if (index < 0) {
index = resultPatterns.size() + (index % (resultPatterns.size() + 1)); //Convert the negative index to a positive reverted index, that starts from the end.
}
index = index % (resultPatterns.size() + 1); //Prevent out of bounds
if (index <= resultPatterns.size()) { // Shouldn't be false! Index out of bounds!
resultPatterns.addAll(index, finalPatterns);
}
}
if (!addExtraFirst.evaluate(evalContext)) {
resultPatterns.addAll(extra(evalContext));
}
bannerResultMeta.setPatterns(resultPatterns);
result.setItemMeta(resultMeta);
return result;
}

@Override
public MergeAdapter clone() {
return new BannerMergeAdapter(this);
}

public static class PatternOption {

private final PatternType type;
private final DyeColor dyeColor;

@JsonCreator
public PatternOption(@JsonProperty("type") PatternType type, @JsonProperty("dyeColor") DyeColor dyeColor) {
this.type = type;
this.dyeColor = dyeColor;
}

public DyeColor getDyeColor() {
return dyeColor;
}

public PatternType getType() {
return type;
}

}

public static class ElementOptionBannerPattern extends ElementOption<Pattern, PatternOption> {

@Override
public boolean isEqual(Pattern value, EvalContext evalContext) {
return value().map(provider -> {
PatternOption option = provider.getValue(evalContext);
return option.type == value.getPattern() && option.dyeColor == value.getColor();
}).orElse(true);
}
}

}
Expand Up @@ -64,7 +64,7 @@ public class BookMetaMergeAdapter extends MergeAdapter {
private BoolOperator copyPages = new BoolOperatorConst(false);
private BoolOperator replacePages = new BoolOperatorConst(false);
private ValueProvider<Integer> insertAtPage = null;
private List<ElementOption> pages = new ArrayList<>();
private List<ElementOptionComponentBukkit> pages = new ArrayList<>();
private List<? extends ValueProvider<String>> extraPages = new ArrayList<>();
private BoolOperator addExtraPagesFirst = new BoolOperatorConst(false);
// Title options
Expand Down Expand Up @@ -109,11 +109,11 @@ public void setReplacePages(BoolOperator replacePages) {
this.replacePages = replacePages;
}

public List<ElementOption> getPages() {
public List<ElementOptionComponentBukkit> getPages() {
return pages;
}

public void setPages(List<ElementOption> pages) {
public void setPages(List<ElementOptionComponentBukkit> pages) {
this.pages = pages;
}

Expand Down Expand Up @@ -252,7 +252,9 @@ public ItemStack merge(RecipeData<?> recipeData, @Nullable Player player, @Nulla

List<String> targetPages = new ArrayList<>(bookMeta.getPages());
if (bookMeta.hasPages() && copyPages.evaluate(evalContext)) {
updatedPages.addAll(ElementOption.constructComponentBasedListFromSource(pages, targetPages, evalContext, miniMessage, papiResolver, langResolver));
for (ElementOptionComponentBukkit page : pages) {
page.readFromSource(targetPages, evalContext, miniMessage, papiResolver, langResolver);
}
}
if (bookMeta.hasTitle()) {
title.append(bookMeta.getTitle());
Expand Down
Expand Up @@ -62,7 +62,7 @@ public class DisplayLoreMergeAdapter extends MergeAdapter {
private boolean replaceLore = false;
@JsonInclude(JsonInclude.Include.NON_NULL)
private ValueProvider<Integer> insertAtIndex = null;
private List<ElementOption> lines;
private List<ElementOptionComponentBukkit> lines;
private List<? extends ValueProvider<String>> extra;
private boolean addExtraFirst = false;

Expand All @@ -80,11 +80,11 @@ public DisplayLoreMergeAdapter(DisplayLoreMergeAdapter adapter) {
this.extra = adapter.extra;
}

public void setLines(List<ElementOption> lines) {
public void setLines(List<ElementOptionComponentBukkit> lines) {
this.lines = lines;
}

public List<ElementOption> getLines() {
public List<ElementOptionComponentBukkit> getLines() {
return lines;
}

Expand Down Expand Up @@ -147,7 +147,9 @@ public ItemStack merge(RecipeData<?> recipeData, @Nullable Player player, @Nulla
if (meta.hasLore()) {
List<String> targetedLore = meta.getLore();
assert targetedLore != null;
finalLore.addAll(ElementOption.constructComponentBasedListFromSource(lines, targetedLore, evalContext, miniMessage, papiResolver, langResolver));
for (ElementOptionComponentBukkit line : lines) {
finalLore.addAll(line.readFromSource(targetedLore, evalContext, miniMessage, papiResolver, langResolver));
}
}
}
List<String> resultLore = resultMeta.hasLore() ? resultMeta.getLore() : new ArrayList<>();
Expand Down
Expand Up @@ -24,26 +24,21 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import me.wolfyscript.lib.com.fasterxml.jackson.annotation.JsonGetter;
import me.wolfyscript.lib.com.fasterxml.jackson.annotation.JsonInclude;
import me.wolfyscript.lib.net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
import me.wolfyscript.lib.net.kyori.adventure.text.Component;
import me.wolfyscript.lib.net.kyori.adventure.text.minimessage.MiniMessage;
import me.wolfyscript.lib.net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import me.wolfyscript.utilities.util.eval.context.EvalContext;
import me.wolfyscript.utilities.util.eval.operators.BoolOperator;
import me.wolfyscript.utilities.util.eval.value_providers.ValueProvider;

public final class ElementOption {
public abstract class ElementOption<O, C> {

@JsonInclude(JsonInclude.Include.NON_NULL)
private ValueProvider<Integer> index;
@JsonInclude(JsonInclude.Include.NON_NULL)
private BoolOperator condition;
@JsonInclude(JsonInclude.Include.NON_NULL)
private ValueProvider<String> value;
private ValueProvider<C> value;

public Optional<ValueProvider<Integer>> index() {
return Optional.ofNullable(index);
Expand Down Expand Up @@ -71,48 +66,48 @@ public BoolOperator getCondition() {
return condition;
}

public Optional<ValueProvider<String>> value() {
public Optional<ValueProvider<C>> value() {
return Optional.ofNullable(value);
}

public void setValue(ValueProvider<String> value) {
public void setValue(ValueProvider<C> value) {
this.value = value;
}

@JsonGetter
ValueProvider<String> getValue() {
return value;
}
public abstract boolean isEqual(O value, EvalContext evalContext);

public static List<String> constructComponentBasedListFromSource(List<ElementOption> elementOptions, List<String> source, EvalContext evalContext, MiniMessage miniMessage, TagResolver... tagResolvers) {
List<String> updatedPages = new ArrayList<>();
for (ElementOption line : elementOptions) {
if (line.condition().map(boolOperator -> boolOperator.evaluate(evalContext)).orElse(true)) {
line.index().ifPresentOrElse(indexProvider -> {
int index = indexProvider.getValue(evalContext);
if (index < 0) {
index = source.size() + (index % source.size()); //Convert the negative index to a positive reverted index, that starts from the end.
}
index = index % source.size(); //Prevent out of bounds
if (source.size() > index) {
String targetValue = source.get(index);
line.value().ifPresentOrElse(valueProvider -> {
if (Objects.equals(miniMessage.deserialize(valueProvider.getValue(evalContext), tagResolvers), BukkitComponentSerializer.legacy().deserialize(targetValue))) {
updatedPages.add(targetValue);
}
}, () -> updatedPages.add(targetValue));
}
}, () -> line.value().ifPresentOrElse(valueProvider -> {
Component value = miniMessage.deserialize(valueProvider.getValue(evalContext), tagResolvers);
for (String targetValue : source) {
if (Objects.equals(value, BukkitComponentSerializer.legacy().deserialize(targetValue))) {
updatedPages.add(targetValue);
public List<O> readFromSource(List<O> source, EvalContext evalContext) {
List<O> result = new ArrayList<>();
if (condition().map(boolOperator -> boolOperator.evaluate(evalContext)).orElse(true)) {
index().ifPresentOrElse(indexProvider -> {
int index = indexProvider.getValue(evalContext);
if (index < 0) {
index = source.size() + (index % source.size()); //Convert the negative index to a positive reverted index, that starts from the end.
}
index = index % source.size(); //Prevent out of bounds
if (source.size() > index) {
O targetValue = source.get(index);
value().ifPresentOrElse(valueProvider -> {
if (isEqual(targetValue, evalContext)) {
result.add(targetValue);
}
}, () -> result.add(targetValue));
}
}, () -> value().ifPresentOrElse(valueProvider -> {
for (O targetValue : source) {
if (isEqual(targetValue, evalContext)) {
result.add(targetValue);
}
}, () -> updatedPages.addAll(source)));
}
}
}, () -> result.addAll(source)));
}
return updatedPages;
return result;
}

@JsonGetter
protected ValueProvider<C> getValue() {
return value;
}

}