Skip to content

Commit

Permalink
Add Material support
Browse files Browse the repository at this point in the history
Signed-off-by: TheSilkMiner <thesilkminer@outlook.com>
  • Loading branch information
TheSilkMiner committed Jun 18, 2022
1 parent a0eaba5 commit 8b3238c
Show file tree
Hide file tree
Showing 6 changed files with 376 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.blamejared.contenttweaker.vanilla.api.util;

import com.google.common.base.Suppliers;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.material.Material;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Stream;

public final class MaterialRegistry {
private static final Supplier<MaterialRegistry> INSTANCE = Suppliers.memoize(
() -> new MaterialRegistry(MaterialRegistry::computeVanillaMaterials)
);

private final BiMap<ResourceLocation, Material> materials;
private final BiMap<Material, ResourceLocation> inverse;

private MaterialRegistry(final Supplier<Map<ResourceLocation, Material>> vanillaMaterialsGetter) {
this.materials = HashBiMap.create(vanillaMaterialsGetter.get());
this.inverse = this.materials.inverse();
}

public static MaterialRegistry of() {
return INSTANCE.get();
}

private static Map<ResourceLocation, Material> computeVanillaMaterials() {
final Map<ResourceLocation, Material> map = new HashMap<>();
entry(map, "air", Material.AIR);
entry(map, "structural_air", Material.STRUCTURAL_AIR);
entry(map, "portal", Material.PORTAL);
entry(map, "cloth_decoration", Material.CLOTH_DECORATION);
entry(map, "plant", Material.PLANT);
entry(map, "water_plant", Material.WATER_PLANT);
entry(map, "replaceable_plant", Material.REPLACEABLE_PLANT);
entry(map, "replaceable_fireproof_plant", Material.REPLACEABLE_FIREPROOF_PLANT);
entry(map, "replaceable_water_plant", Material.REPLACEABLE_WATER_PLANT);
entry(map, "water", Material.WATER);
entry(map, "bubble_column", Material.BUBBLE_COLUMN);
entry(map, "lava", Material.LAVA);
entry(map, "top_snow", Material.TOP_SNOW);
entry(map, "fire", Material.FIRE);
entry(map, "decoration", Material.DECORATION);
entry(map, "web", Material.WEB);
entry(map, "sculk", Material.SCULK);
entry(map, "buildable_glass", Material.BUILDABLE_GLASS);
entry(map, "clay", Material.CLAY);
entry(map, "dirt", Material.DIRT);
entry(map, "grass", Material.GRASS);
entry(map, "ice_solid", Material.ICE_SOLID);
entry(map, "sand", Material.SAND);
entry(map, "sponge", Material.SPONGE);
entry(map, "shulker_shell", Material.SHULKER_SHELL);
entry(map, "wood", Material.WOOD);
entry(map, "nether_wood", Material.NETHER_WOOD);
entry(map, "bamboo_sapling", Material.BAMBOO_SAPLING);
entry(map, "bamboo", Material.BAMBOO);
entry(map, "wool", Material.WOOL);
entry(map, "explosive", Material.EXPLOSIVE);
entry(map, "leaves", Material.LEAVES);
entry(map, "glass", Material.GLASS);
entry(map, "ice", Material.ICE);
entry(map, "cactus", Material.CACTUS);
entry(map, "stone", Material.STONE);
entry(map, "metal", Material.METAL);
entry(map, "snow", Material.SNOW);
entry(map, "heavy_metal", Material.HEAVY_METAL);
entry(map, "barrier", Material.BARRIER);
entry(map, "piston", Material.PISTON);
entry(map, "moss", Material.MOSS);
entry(map, "vegetable", Material.VEGETABLE);
entry(map, "egg", Material.EGG);
entry(map, "cake", Material.CAKE);
entry(map, "amethyst", Material.AMETHYST);
entry(map, "powder_snow", Material.POWDER_SNOW);
return map;
}

private static void entry(final Map<ResourceLocation, Material> map, final String name, final Material material) {
map.put(new ResourceLocation(name.toLowerCase(Locale.ENGLISH)), material);
}

public Material register(final ResourceLocation name, final Supplier<Material> creator) {
Objects.requireNonNull(creator);
if (this.materials.containsKey(Objects.requireNonNull(name))) {
throw new IllegalArgumentException("A tier with name " + name + " is already known");
}
final Material material = Objects.requireNonNull(creator.get());
this.materials.put(name, material);
return material;
}

public Material find(final ResourceLocation name) {
return this.materials.computeIfAbsent(name, it -> {
throw new IllegalArgumentException("No such material found for id " + it);
});
}

public Stream<ResourceLocation> knownMaterials() {
return this.materials.keySet().stream();
}

public ResourceLocation nameOf(final Material material) {
return this.inverse.computeIfAbsent(material, it -> {
throw new IllegalArgumentException("No such material " + it + " known: it is probably not registered");
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package com.blamejared.contenttweaker.vanilla.api.zen.util;

import com.blamejared.contenttweaker.core.api.ContentTweakerApi;
import com.blamejared.contenttweaker.core.api.ContentTweakerConstants;
import com.blamejared.contenttweaker.vanilla.api.action.material.CreateMaterialAction;
import com.blamejared.contenttweaker.vanilla.api.util.MaterialRegistry;
import com.blamejared.contenttweaker.vanilla.api.zen.ContentTweakerVanillaConstants;
import com.blamejared.crafttweaker.api.CraftTweakerAPI;
import com.blamejared.crafttweaker.api.annotation.ZenRegister;
import com.blamejared.crafttweaker.api.util.NameUtil;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.PushReaction;
import org.openzen.zencode.java.ZenCodeType;

import java.util.Objects;
import java.util.Optional;

@ZenCodeType.Name(ContentTweakerVanillaConstants.VANILLA_UTIL_PACKAGE + ".MaterialBuilder")
@ZenRegister(loaders = ContentTweakerConstants.CONTENT_LOADER_ID)
public final class MaterialBuilder {
private final MaterialColorReference color;

private PushReaction pushReaction;
private boolean blocksMotion;
private boolean flammable;
private boolean liquid;
private boolean replaceable;
private boolean solid;
private boolean solidBlocking;

private MaterialBuilder(final MaterialColorReference reference) {
this.color = reference;
this.pushReaction = null;
this.blocksMotion = false;
this.flammable = false;
this.liquid = false;
this.replaceable = false;
this.solid = false;
this.solidBlocking = false;
}

public static MaterialBuilder of(final MaterialColorReference reference) {
return new MaterialBuilder(Objects.requireNonNull(reference));
}

@ZenCodeType.Method("pushReaction")
public MaterialBuilder pushReaction(final PushReaction reaction) {
this.pushReaction = Objects.requireNonNull(reaction);
return this;
}

@ZenCodeType.Method("blocksMotion")
public MaterialBuilder blocksMotion() {
this.blocksMotion = true;
return this;
}

@ZenCodeType.Method("flammable")
public MaterialBuilder flammable() {
this.flammable = true;
return this;
}

@ZenCodeType.Method("liquid")
public MaterialBuilder liquid() {
this.liquid = true;
return this;
}

@ZenCodeType.Method("replaceable")
public MaterialBuilder replaceable() {
this.replaceable = true;
return this;
}

@ZenCodeType.Method("solid")
public MaterialBuilder solid() {
this.solid = true;
return this;
}

@ZenCodeType.Method("solidBlocking")
public MaterialBuilder solidBlocking() {
this.solidBlocking = true;
return this;
}

@ZenCodeType.Method("build")
public MaterialReference build(final String name) {
final ResourceLocation id = ContentTweakerConstants.rl(
NameUtil.fixing(
name,
(fix, mistakes) -> CraftTweakerAPI.LOGGER.warn(
"The given name '{}' is not valid: it has been fixed to '{}'.\nMistakes:\n{}",
name,
fix,
String.join("\n", mistakes)
)
)
);
return MaterialReference.of(id, () -> {
final Material[] material = new Material[1];
ContentTweakerApi.apply(CreateMaterialAction.of(id, () -> material[0] = MaterialRegistry.of().register(id, this::make)));
return material[0];
});
}

private Material make() {
return new Material(
this.color.unwrap(),
this.liquid,
this.solid,
this.blocksMotion,
this.solidBlocking,
this.flammable,
this.replaceable,
Optional.ofNullable(this.pushReaction).orElse(PushReaction.NORMAL)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.blamejared.contenttweaker.vanilla.api.zen.util;

import com.blamejared.contenttweaker.core.api.ContentTweakerConstants;
import com.blamejared.contenttweaker.vanilla.api.zen.ContentTweakerVanillaConstants;
import com.blamejared.crafttweaker.api.annotation.ZenRegister;
import com.google.common.base.Suppliers;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.material.Material;
import org.openzen.zencode.java.ZenCodeType;

import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;

@ZenCodeType.Name(ContentTweakerVanillaConstants.VANILLA_UTIL_PACKAGE + ".MaterialReference")
@ZenRegister(loaders = ContentTweakerConstants.CONTENT_LOADER_ID)
public final class MaterialReference {
private final ResourceLocation name;
private final Supplier<Material> lookupManager;

private MaterialReference(final ResourceLocation name, final Supplier<Material> lookupManager) {
this.name = name;
this.lookupManager = lookupManager;
}

public static MaterialReference of(final ResourceLocation name, final Supplier<Material> lookupManager) {
return new MaterialReference(Objects.requireNonNull(name), Suppliers.memoize(Objects.requireNonNull(lookupManager)::get));
}

public static MaterialReference of(final ResourceLocation name, final Function<ResourceLocation, Material> lookupFunction) {
Objects.requireNonNull(name);
Objects.requireNonNull(lookupFunction);
return of(name, () -> lookupFunction.apply(name));
}

@ZenCodeType.Method("builder")
public static MaterialBuilder builder(final MaterialColorReference reference) {
return MaterialBuilder.of(reference);
}

@ZenCodeType.Getter("name")
public ResourceLocation name() {
return this.name;
}

public Material unwrap() {
return this.lookupManager.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ private ContentTweakerVanillaBrackets() {}
public static void register(final CustomBracketRegistration registration) {
registration.registerBracket("item", new ItemBracketExpressionParser()); // Dump already available through CT
registration.registerBracket("tab", new CreativeTabBracketExpressionParser(), CreativeTabBracketExpressionParser::dump);
registration.registerBracket("material", new MaterialBracketExpressionParser(), MaterialBracketExpressionParser::dump);
registration.registerBracket("materialcolor", new MaterialColorBracketExpressionParser(), MaterialColorBracketExpressionParser::dump);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.blamejared.contenttweaker.vanilla.zen.bracket;

import com.blamejared.contenttweaker.core.api.zen.bracket.BracketHelper;
import com.blamejared.contenttweaker.vanilla.api.util.MaterialRegistry;
import com.blamejared.contenttweaker.vanilla.zen.rt.MaterialMetaFactory;
import com.blamejared.crafttweaker.api.util.ParseUtil;
import net.minecraft.resources.ResourceLocation;
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 java.util.Collections;
import java.util.Objects;
import java.util.stream.Stream;

final class MaterialBracketExpressionParser implements BracketExpressionParser {
private static final class MaterialMetaFactoryExpression extends ParsedExpression {
private final ResourceLocation id;

MaterialMetaFactoryExpression(final CodePosition position, final ResourceLocation id) {
super(position);
this.id = id;
}

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

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

static Stream<String> dump() {
return MaterialRegistry.of()
.knownMaterials()
.map(Objects::toString)
.map("<material:%s>"::formatted);
}

@Override
public ParsedExpression parse(final CodePosition position, final ZSTokenParser tokens) throws ParseException {
final String contents = ParseUtil.readBracketContent(position, tokens);
final ResourceLocation location = BracketHelper.locationOrThrow(
position,
contents,
() -> "Expected a material in the form <material:modid:name>, but got <material:%s>".formatted(contents)
);
return new MaterialMetaFactoryExpression(position, location);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.blamejared.contenttweaker.vanilla.zen.rt;

import com.blamejared.contenttweaker.core.api.ContentTweakerConstants;
import com.blamejared.contenttweaker.vanilla.api.util.MaterialRegistry;
import com.blamejared.contenttweaker.vanilla.api.zen.ContentTweakerVanillaConstants;
import com.blamejared.contenttweaker.vanilla.api.zen.util.MaterialReference;
import com.blamejared.crafttweaker.api.annotation.ZenRegister;
import net.minecraft.resources.ResourceLocation;
import org.openzen.zencode.java.ZenCodeType;

import java.util.Objects;

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

private MaterialMetaFactory() {}

@ZenCodeType.Method
public static MaterialReference factory(final ResourceLocation name) {
return MaterialReference.of(Objects.requireNonNull(name), id -> MaterialRegistry.of().find(id));
}
}

0 comments on commit 8b3238c

Please sign in to comment.