Block consumer patch support

This commit is contained in:
Anuken
2025-10-22 20:04:00 -04:00
parent f3cac6a6bc
commit effbdecbd5
4 changed files with 84 additions and 43 deletions

View File

@@ -442,6 +442,52 @@ public class ContentParser{
}
};
public void readBlockConsumers(Block block, JsonValue value){
for(JsonValue child : value){
switch(child.name){
case "remove" -> {
String[] values = child.isString() ? new String[]{child.asString()} : child.asStringArray();
for(String type : values){
Class<?> consumeType = resolve("Consume" + Strings.capitalize(type), Consume.class);
if(consumeType != Consume.class){
block.removeConsumers(b -> consumeType.isAssignableFrom(b.getClass()));
}else{
Log.warn("Unknown consumer type '@' (Class: @) in consume: remove.", type, "Consume" + Strings.capitalize(type));
}
}
}
case "item" -> block.consumeItem(find(ContentType.item, child.asString()));
case "itemCharged" -> block.consume((Consume)parser.readValue(ConsumeItemCharged.class, child));
case "itemFlammable" -> block.consume((Consume)parser.readValue(ConsumeItemFlammable.class, child));
case "itemRadioactive" -> block.consume((Consume)parser.readValue(ConsumeItemRadioactive.class, child));
case "itemExplosive" -> block.consume((Consume)parser.readValue(ConsumeItemExplosive.class, child));
case "itemList" -> block.consume((Consume)parser.readValue(ConsumeItemList.class, child));
case "itemExplode" -> block.consume((Consume)parser.readValue(ConsumeItemExplode.class, child));
case "items" -> block.consume(
child.isArray() ? new ConsumeItems(parser.readValue(ItemStack[].class, child)) :
child.isString() ? new ConsumeItems(new ItemStack[]{parser.readValue(ItemStack.class, child)}) :
parser.readValue(ConsumeItems.class, child));
case "liquidFlammable" -> block.consume((Consume)parser.readValue(ConsumeLiquidFlammable.class, child));
case "liquid" -> block.consume((Consume)parser.readValue(ConsumeLiquid.class, child));
case "liquids" -> block.consume(
child.isArray() ? new ConsumeLiquids(parser.readValue(LiquidStack[].class, child)) :
parser.readValue(ConsumeLiquids.class, child));
case "coolant" -> block.consume((Consume)parser.readValue(ConsumeCoolant.class, child));
case "power" -> {
if(child.isNumber()){
block.consumePower(child.asFloat());
}else{
block.consume((Consume)parser.readValue(ConsumePower.class, child));
}
}
case "powerBuffered" -> block.consumePowerBuffered(child.asFloat());
default -> throw new IllegalArgumentException("Unknown consumption type: '" + child.name + "' for block '" + block.name + "'.");
}
}
value.remove("consumes");
}
private ObjectMap<ContentType, TypeParser<?>> parsers = ObjectMap.of(
ContentType.block, (TypeParser<Block>)(mod, name, value) -> {
readBundle(ContentType.block, name, value);
@@ -463,46 +509,7 @@ public class ContentParser{
read(() -> {
if(value.has("consumes") && value.get("consumes").isObject()){
for(JsonValue child : value.get("consumes")){
switch(child.name){
case "remove" -> {
String[] values = child.isString() ? new String[]{child.asString()} : child.asStringArray();
for(String type : values){
Class<?> consumeType = resolve("Consume" + Strings.capitalize(type), Consume.class);
if(consumeType != Consume.class){
block.removeConsumers(b -> consumeType.isAssignableFrom(b.getClass()));
}else{
Log.warn("Unknown consumer type '@' (Class: @) in consume: remove.", type, "Consume" + Strings.capitalize(type));
}
}
}
case "item" -> block.consumeItem(find(ContentType.item, child.asString()));
case "itemCharged" -> block.consume((Consume)parser.readValue(ConsumeItemCharged.class, child));
case "itemFlammable" -> block.consume((Consume)parser.readValue(ConsumeItemFlammable.class, child));
case "itemRadioactive" -> block.consume((Consume)parser.readValue(ConsumeItemRadioactive.class, child));
case "itemExplosive" -> block.consume((Consume)parser.readValue(ConsumeItemExplosive.class, child));
case "itemList" -> block.consume((Consume)parser.readValue(ConsumeItemList.class, child));
case "itemExplode" -> block.consume((Consume)parser.readValue(ConsumeItemExplode.class, child));
case "items" -> block.consume(child.isArray() ?
new ConsumeItems(parser.readValue(ItemStack[].class, child)) :
parser.readValue(ConsumeItems.class, child));
case "liquidFlammable" -> block.consume((Consume)parser.readValue(ConsumeLiquidFlammable.class, child));
case "liquid" -> block.consume((Consume)parser.readValue(ConsumeLiquid.class, child));
case "liquids" -> block.consume(child.isArray() ?
new ConsumeLiquids(parser.readValue(LiquidStack[].class, child)) :
parser.readValue(ConsumeLiquids.class, child));
case "coolant" -> block.consume((Consume)parser.readValue(ConsumeCoolant.class, child));
case "power" -> {
if(child.isNumber()){
block.consumePower(child.asFloat());
}else{
block.consume((Consume)parser.readValue(ConsumePower.class, child));
}
}
case "powerBuffered" -> block.consumePowerBuffered(child.asFloat());
default -> throw new IllegalArgumentException("Unknown consumption type: '" + child.name + "' for block '" + block.name + "'.");
}
}
readBlockConsumers(block, value.get("consumes"));
value.remove("consumes");
}

View File

@@ -9,12 +9,13 @@ import arc.util.serialization.Jval.*;
import mindustry.*;
import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.world.*;
import mindustry.world.consumers.*;
import java.lang.reflect.*;
import java.util.*;
/** The current implementation is awful. Consider it a proof of concept. */
//TODO block consumer support
@SuppressWarnings("unchecked")
public class ContentPatcher{
private static final Object root = new Object();
@@ -113,7 +114,7 @@ public class ContentPatcher{
for(int i = 0; i < path.length - 1; i++){
Object[] result = resolve(object, path[i], metadata);
if(result == null){
//TODO report error
warn("Failed to resolve @.@", object, path[i]);
return;
}
object = result[0];
@@ -231,6 +232,23 @@ public class ContentPatcher{
}
Reflect.set(fobj, fdata.field, fv);
}, value, true);
}else if(value instanceof JsonValue jsv && object instanceof Block bl && jsv.isObject() && field.equals("consumes")){
modifiedField(bl, "consumeBuilder", Reflect.<Seq<Consume>>get(Block.class, bl, "consumeBuilder").copy());
boolean hadItems = bl.hasItems, hadLiquids = bl.hasLiquids, hadPower = bl.hasPower, acceptedItems = bl.acceptsItems;
reset(() -> {
bl.hasItems = hadItems;
bl.hasLiquids = hadLiquids;
bl.hasPower = hadPower;
bl.acceptsItems = acceptedItems;
});
after(bl::reinitializeConsumers);
try{
Vars.mods.getContentParser().readBlockConsumers(bl, jsv);
}catch(Throwable e){
Log.err(e);
warn("Failed to read consumers for '@': @", bl, Strings.getSimpleMessage(e));
}
}else{
warn("Unknown field: '@' for class '@'", field, actualType.getSimpleName());
}
@@ -241,7 +259,7 @@ public class ContentPatcher{
Object prevValue = getter.get();
if(value instanceof JsonValue jsv){ //setting values from object
if(prevValue == null || !jsv.isObject() || jsv.has("type")){
if(prevValue == null || !jsv.isObject() || jsv.has("type")){
if(UnlockableContent.class.isAssignableFrom(metadata.type) && (jsv.isObject())){
warn("New content must not be instantiated: @", jsv);
return;