Преглед на файлове

New: Reduce wasted memory in SimpleBakedModel quad lists
This is a minor optimization (usually <=20MB), but is easy to implement and should not break anything

malte0811 преди 2 години
родител
ревизия
b63de54a7c

+ 37 - 0
Common/src/main/java/malte0811/ferritecore/impl/ModelSidesImpl.java

@@ -0,0 +1,37 @@
+package malte0811.ferritecore.impl;
+
+import net.minecraft.Util;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.core.Direction;
+
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Use immutable lists for all quad lists. The backing array will exactly match the list size, and all empty lists will
+ * use the same list instance. Additionally, the shallow size will be smaller than that of an ArrayList (otherwise
+ * ArrayList#trimToSize could be used)
+ */
+public class ModelSidesImpl {
+    private static final Direction[] SIDES = Direction.values();
+    private static final Map<Direction, List<BakedQuad>> EMPTY = Util.make(new EnumMap<>(Direction.class), m -> {
+        for (Direction side : SIDES) {
+            m.put(side, List.of());
+        }
+    });
+
+    public static List<BakedQuad> minimizeUnculled(List<BakedQuad> quads) {
+        return List.copyOf(quads);
+    }
+
+    public static Map<Direction, List<BakedQuad>> minimizeCulled(Map<Direction, List<BakedQuad>> quadsBySide) {
+        boolean allEmpty = true;
+        for (final var face : SIDES) {
+            final var sideQuads = quadsBySide.get(face);
+            quadsBySide.put(face, List.copyOf(sideQuads));
+            allEmpty &= sideQuads.isEmpty();
+        }
+        return allEmpty ? EMPTY : quadsBySide;
+    }
+}

+ 5 - 0
Common/src/main/java/malte0811/ferritecore/mixin/config/FerriteConfig.java

@@ -20,6 +20,7 @@ public class FerriteConfig {
     public static final Option COMPACT_FAST_MAP;
     public static final Option POPULATE_NEIGHBOR_TABLE;
     public static final Option THREADING_DETECTOR;
+    public static final Option MODEL_SIDES;
 
     static {
         ConfigBuilder builder = new ConfigBuilder();
@@ -52,6 +53,10 @@ public class FerriteConfig {
                 "bakedQuadDeduplication",
                 "Deduplicate vertex data of baked quads in the basic model implementations"
         );
+        MODEL_SIDES = builder.createOption(
+                "modelSides",
+                "Use smaller data structures for \"simple\" models, especially models with few side-specific faces"
+        );
         THREADING_DETECTOR = builder.createOptInOption(
                 "useSmallThreadingDetector",
                 "Replace objects used to detect multi-threaded access to chunks by a much smaller field. This option" +

+ 10 - 0
Common/src/main/java/malte0811/ferritecore/mixin/modelsides/Config.java

@@ -0,0 +1,10 @@
+package malte0811.ferritecore.mixin.modelsides;
+
+import malte0811.ferritecore.mixin.config.FerriteConfig;
+import malte0811.ferritecore.mixin.config.FerriteMixinConfig;
+
+public class Config extends FerriteMixinConfig {
+    public Config() {
+        super(FerriteConfig.MODEL_SIDES);
+    }
+}

+ 36 - 0
Common/src/main/java/malte0811/ferritecore/mixin/modelsides/SimpleBakedModelMixin.java

@@ -0,0 +1,36 @@
+package malte0811.ferritecore.mixin.modelsides;
+
+import malte0811.ferritecore.impl.ModelSidesImpl;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.resources.model.SimpleBakedModel;
+import net.minecraft.core.Direction;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Mutable;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import java.util.List;
+import java.util.Map;
+
+@Mixin(SimpleBakedModel.class)
+public class SimpleBakedModelMixin {
+    @Shadow
+    @Final
+    @Mutable
+    protected Map<Direction, List<BakedQuad>> culledFaces;
+
+    @Shadow
+    @Final
+    @Mutable
+    protected List<BakedQuad> unculledFaces;
+
+    // Target all constructors, Forge adds an argument to the "main" constructor
+    @Inject(method = "/<init>/", at = @At("TAIL"))
+    private void minimizeFaceLists(CallbackInfo ci) {
+        this.unculledFaces = ModelSidesImpl.minimizeUnculled(this.unculledFaces);
+        this.culledFaces = ModelSidesImpl.minimizeCulled(this.culledFaces);
+    }
+}

+ 14 - 0
Common/src/main/resources/ferritecore.modelsides.mixin.json

@@ -0,0 +1,14 @@
+{
+  "required": true,
+  "package": "malte0811.ferritecore.mixin.modelsides",
+  "compatibilityLevel": "JAVA_17",
+  "client": [
+    "SimpleBakedModelMixin"
+  ],
+  "injectors": {
+    "defaultRequire": 1
+  },
+  "minVersion": "0.8",
+  "plugin": "malte0811.ferritecore.mixin.modelsides.Config",
+  "refmap": "${refmap_target}refmap.json"
+}

+ 1 - 0
Fabric/src/main/resources/fabric.mod.json

@@ -30,6 +30,7 @@
     "ferritecore.predicates.mixin.json",
     "ferritecore.dedupbakedquad.mixin.json",
     "ferritecore.threaddetec.mixin.json",
+    "ferritecore.modelsides.mixin.json",
     "ferritecore.fabric.mixin.json"
   ],
   "custom": {

+ 1 - 0
Forge/build.gradle

@@ -27,6 +27,7 @@ def fcMixinConfigs = [
         "blockstatecache",
         "dedupbakedquad",
         "threaddetec",
+        "modelsides",
 ].stream()
         .<String> map({ s -> "ferritecore." + s + ".mixin.json" })
         .collect(Collectors.toList())