Skip to content

Commit

Permalink
Add custom creative tab API
Browse files Browse the repository at this point in the history
Signed-off-by: TheSilkMiner <thesilkminer@outlook.com>
  • Loading branch information
TheSilkMiner committed May 21, 2022
1 parent 1fa8618 commit dfb8968
Show file tree
Hide file tree
Showing 10 changed files with 323 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.blamejared.contenttweaker.vanilla.api.action.tab;

import com.blamejared.contenttweaker.core.api.action.ContentTweakerAction;
import org.apache.logging.log4j.Logger;

import java.util.Objects;

public final class CreateCreativeTabAction implements ContentTweakerAction {
private final String name;
private final Runnable tabCreator;

private CreateCreativeTabAction(final String name, final Runnable tabCreator) {
this.name = name;
this.tabCreator = tabCreator;
}

public static CreateCreativeTabAction of(final String name, final Runnable tabCreator) {
return new CreateCreativeTabAction(Objects.requireNonNull(name), Objects.requireNonNull(tabCreator));
}

@Override
public void apply() {
this.tabCreator.run();
}

@Override
public String describe() {
return "Creating new creative tab with ID " + this.name;
}

@Override
public boolean validate(final Logger logger) {
return true; // TODO("")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.blamejared.contenttweaker.vanilla.api.action.tab;

import com.blamejared.contenttweaker.core.api.action.ContentTweakerAction;
import com.blamejared.contenttweaker.vanilla.api.util.ContentTweakerCreativeTab;
import com.blamejared.contenttweaker.vanilla.api.zen.object.ItemReference;
import com.blamejared.contenttweaker.vanilla.api.zen.util.CreativeTab;
import org.apache.logging.log4j.Logger;

import java.util.Objects;

public final class SetCreativeTabIconAction implements ContentTweakerAction {
private final CreativeTab tab;
private final ItemReference icon;

private SetCreativeTabIconAction(final CreativeTab tab, final ItemReference icon) {
this.tab = tab;
this.icon = icon;
}

public static SetCreativeTabIconAction of(final CreativeTab tab, final ItemReference icon) {
return new SetCreativeTabIconAction(Objects.requireNonNull(tab), Objects.requireNonNull(icon));
}

@Override
public void apply() {
((ContentTweakerCreativeTab) this.tab.unwrap()).setDisplayItem(this.icon);
}

@Override
public String describe() {
return "Setting icon of tab %s to %s".formatted(this.tab, this.icon.id());
}

@Override
public boolean validate(final Logger logger) {
if (!(this.tab.unwrap() instanceof ContentTweakerCreativeTab)) {
logger.error("Creative tab " + this.tab + " is not customizable");
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.blamejared.contenttweaker.vanilla.api.util;

import com.blamejared.contenttweaker.vanilla.api.zen.object.ItemReference;

public interface ContentTweakerCreativeTab {
void setDisplayItem(final ItemReference stack);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.blamejared.contenttweaker.vanilla.api.zen.util;

import com.blamejared.contenttweaker.core.api.ContentTweakerConstants;
import com.blamejared.contenttweaker.vanilla.api.action.tab.SetCreativeTabIconAction;
import com.blamejared.contenttweaker.vanilla.api.zen.ContentTweakerVanillaConstants;
import com.blamejared.contenttweaker.vanilla.api.zen.object.ItemReference;
import com.blamejared.contenttweaker.vanilla.mixin.CreativeModeTabAccessor;
import com.blamejared.crafttweaker.api.CraftTweakerAPI;
import com.blamejared.crafttweaker.api.annotation.ZenRegister;
import net.minecraft.world.item.CreativeModeTab;
import org.openzen.zencode.java.ZenCodeType;

import java.util.Objects;

@ZenCodeType.Name(ContentTweakerVanillaConstants.VANILLA_UTIL_PACKAGE + ".CreativeTab")
@ZenRegister(loaders = ContentTweakerConstants.CONTENT_LOADER_ID)
public final class CreativeTab {
private final CreativeModeTab internal;

private CreativeTab(final CreativeModeTab tab) {
this.internal = tab;
}

public static CreativeTab wrap(final CreativeModeTab wrapped) {
return new CreativeTab(Objects.requireNonNull(wrapped));
}

@ZenCodeType.Getter("id")
public String id() {
return ((CreativeModeTabAccessor) this.internal).contenttweaker$langId();
}

@ZenCodeType.Setter("icon")
public void icon(final ItemReference icon) {
CraftTweakerAPI.apply(SetCreativeTabIconAction.of(this, icon));
}

public CreativeModeTab unwrap() {
return this.internal;
}

@Override
public String toString() {
return this.id();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.blamejared.contenttweaker.vanilla.mixin;

import net.minecraft.world.item.CreativeModeTab;
import org.spongepowered.asm.mixin.Debug;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;

@Debug(export = true)
@Mixin(CreativeModeTab.class)
public interface CreativeModeTabAccessor {
@Accessor("langId")
String contenttweaker$langId();

@Accessor("TABS")
@Mutable
static void contenttweaker$tabs(final CreativeModeTab[] tabs) {
throw new UnsupportedOperationException("Mixin not applied");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.blamejared.contenttweaker.vanilla.util;

import com.blamejared.contenttweaker.vanilla.api.util.ContentTweakerCreativeTab;
import com.blamejared.contenttweaker.vanilla.api.zen.object.ItemReference;
import com.blamejared.contenttweaker.vanilla.mixin.CreativeModeTabAccessor;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;

import java.util.Objects;

public final class CustomCreativeTab extends CreativeModeTab implements ContentTweakerCreativeTab {
private ItemReference displayItem;
private ItemStack cache;

private CustomCreativeTab(final int id, final String langId, final ItemReference displayItem) {
super(id, langId);
this.displayItem = Objects.requireNonNull(displayItem);
this.cache = null;
}

public static CreativeModeTab of(final String name) {
Objects.requireNonNull(name);
final int id = expand();
return new CustomCreativeTab(id, name, ItemReference.AIR);
}

private static int expand() {
final CreativeModeTab[] tabs = CreativeModeTab.TABS;
final int length = tabs.length;
final CreativeModeTab[] newTabs = new CreativeModeTab[length + 1];
System.arraycopy(tabs, 0, newTabs, 0, length);
newTabs[length] = null;
CreativeModeTabAccessor.contenttweaker$tabs(newTabs);
return length;
}

@Override
public void setDisplayItem(final ItemReference stack) {
this.displayItem = Objects.requireNonNull(stack);
this.cache = null;
}

@Override
public ItemStack getIconItem() {
if (this.cache == null) {
this.cache = this.makeIcon();
}
return this.cache;
}

@Override
public ItemStack makeIcon() {
return new ItemStack(this.displayItem.get());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.blamejared.contenttweaker.vanilla.zen.bracket;

import com.blamejared.contenttweaker.vanilla.mixin.CreativeModeTabAccessor;
import com.blamejared.contenttweaker.vanilla.zen.rt.TabMetaFactory;
import com.blamejared.crafttweaker.api.util.ParseUtil;
import com.google.common.base.CaseFormat;
import net.minecraft.world.item.CreativeModeTab;
import org.openzen.zencode.shared.CodePosition;
import org.openzen.zencode.shared.CompileException;
import org.openzen.zenscript.codemodel.partial.IPartialExpression;
import org.openzen.zenscript.codemodel.scope.ExpressionScope;
import org.openzen.zenscript.lexer.ParseException;
import org.openzen.zenscript.lexer.ZSTokenParser;
import org.openzen.zenscript.parser.BracketExpressionParser;
import org.openzen.zenscript.parser.expression.ParsedCallArguments;
import org.openzen.zenscript.parser.expression.ParsedExpression;
import org.openzen.zenscript.parser.expression.ParsedExpressionCall;
import org.openzen.zenscript.parser.expression.ParsedExpressionMember;
import org.openzen.zenscript.parser.expression.ParsedExpressionString;

import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Stream;

final class CreativeTabBracketExpressionParser implements BracketExpressionParser {
private static final class InvokeTabMetaFactoryExpression extends ParsedExpression {
private final String name;

InvokeTabMetaFactoryExpression(final CodePosition position, final String name) {
super(position);
this.name = name;
}

@Override
public IPartialExpression compile(final ExpressionScope scope) throws CompileException {
final ParsedExpression runtimeClass = ParseUtil.staticMemberExpression(this.position, TabMetaFactory.ZEN_NAME);
final ParsedExpression factoryMethod = new ParsedExpressionMember(this.position, runtimeClass, "factory", null);
final ParsedExpression name = new ParsedExpressionString(this.position, this.name, false);
final ParsedCallArguments arguments = new ParsedCallArguments(Collections.emptyList(), Collections.singletonList(name));
final ParsedExpression invocation = new ParsedExpressionCall(this.position, factoryMethod, arguments);
return invocation.compile(scope);
}

@Override
public boolean hasStrongType() {
return true;
}
}

static Stream<String> dump() {
return Arrays.stream(CreativeModeTab.TABS)
.map(CreativeModeTabAccessor.class::cast)
.map(CreativeModeTabAccessor::contenttweaker$langId)
.map(CaseFormat.LOWER_CAMEL.converterTo(CaseFormat.LOWER_UNDERSCORE)::convert)
.map("<tab:%s>"::formatted);
}

@Override
public ParsedExpression parse(final CodePosition position, final ZSTokenParser tokens) throws ParseException {
final String tabName = ParseUtil.readBracketContent(position, tokens);
return new InvokeTabMetaFactoryExpression(position, tabName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.blamejared.contenttweaker.vanilla.zen.rt;

import com.blamejared.contenttweaker.core.api.ContentTweakerConstants;
import com.blamejared.contenttweaker.vanilla.api.action.tab.CreateCreativeTabAction;
import com.blamejared.contenttweaker.vanilla.api.zen.ContentTweakerVanillaConstants;
import com.blamejared.contenttweaker.vanilla.api.zen.util.CreativeTab;
import com.blamejared.contenttweaker.vanilla.mixin.CreativeModeTabAccessor;
import com.blamejared.contenttweaker.vanilla.util.CustomCreativeTab;
import com.blamejared.crafttweaker.api.CraftTweakerAPI;
import com.blamejared.crafttweaker.api.annotation.ZenRegister;
import net.minecraft.world.item.CreativeModeTab;
import org.openzen.zencode.java.ZenCodeType;

import java.util.Arrays;
import java.util.Objects;

@ZenCodeType.Name(TabMetaFactory.ZEN_NAME)
@ZenRegister(loaders = ContentTweakerConstants.CONTENT_LOADER_ID)
public final class TabMetaFactory {
public static final String ZEN_NAME = ContentTweakerVanillaConstants.VANILLA_RT_PACKAGE + ".TabMetaFactory";

private TabMetaFactory() {}

@ZenCodeType.Method("factory")
public static CreativeTab factory(final String name) {
Objects.requireNonNull(name);
final CreativeModeTab target = Arrays.stream(CreativeModeTab.TABS)
.filter(it -> name.equals(((CreativeModeTabAccessor) it).contenttweaker$langId()))
.findFirst()
.orElseGet(() -> {
final CreativeModeTab[] tab = new CreativeModeTab[1];
final CreateCreativeTabAction action = CreateCreativeTabAction.of(name, () -> tab[0] = CustomCreativeTab.of(name));
CraftTweakerAPI.apply(action);
return tab[0];
});
return CreativeTab.wrap(target);
}
}
13 changes: 13 additions & 0 deletions Common/src/main/resources/contenttweaker.vanilla.mixins.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"required": true,
"compatibilityLevel": "JAVA_17",
"minVersion": "0.8",
"package": "com.blamejared.contenttweaker.vanilla.mixin",
"refmap": "contenttweaker.refmap.json",
"mixins": [
"CreativeModeTabAccessor"
],
"injectors": {
"defaultRequire": 1
}
}
7 changes: 4 additions & 3 deletions Forge/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ minecraft {
create("client") {
workingDirectory(project.file("run"))
ideaModule("${rootProject.name}.${project.name}.main")
args("-mixin.config=${modId}.forge.mixins.json")
sequenceOf("forge", "core", "vanilla").forEach { arg("-mixin.config=${modId}.$it.mixins.json") }
mods {
create(modId) {
source(sourceSets.main.get())
Expand All @@ -40,7 +40,8 @@ minecraft {
create("server") {
workingDirectory(project.file("run_server"))
ideaModule("${rootProject.name}.${project.name}.main")
args("-mixin.config=${modId}.forge.mixins.json", "nogui")
sequenceOf("forge", "core", "vanilla").forEach { arg("-mixin.config=${modId}.$it.mixins.json") }
arg("nogui")
mods {
create(modId) {
source(sourceSets.main.get())
Expand All @@ -54,7 +55,7 @@ minecraft {
mixin {
add(sourceSets.main.get(), "${modId}.refmap.json")

config("${modId}.forge.mixins.json")
sequenceOf("forge", "core", "vanilla").forEach { config("${modId}.$it.mixins.json") }
}

modTemplate {
Expand Down

0 comments on commit dfb8968

Please sign in to comment.