Allow concurrent retrieval of models from the cache

This commit is contained in:
embeddedt 2023-04-09 14:03:32 -04:00
parent e5cd9f57b5
commit 882f4832df
No known key found for this signature in database
GPG Key ID: A69433EC199B5613

View File

@ -236,67 +236,77 @@ public abstract class ModelBakeryMixin {
* @reason synchronize * @reason synchronize
*/ */
@Overwrite @Overwrite
public synchronized UnbakedModel getModel(ResourceLocation modelLocation) { public UnbakedModel getModel(ResourceLocation modelLocation) {
if(modelLocation.equals(MISSING_MODEL_LOCATION)) if(modelLocation.equals(MISSING_MODEL_LOCATION))
return missingModel; return missingModel;
if (this.unbakedCache.containsKey(modelLocation)) { UnbakedModel existing = this.unbakedCache.get(modelLocation);
return this.unbakedCache.get(modelLocation); if (existing != null) {
} else if (this.loadingStack.contains(modelLocation)) { return existing;
throw new IllegalStateException("Circular reference while loading " + modelLocation);
} else { } else {
this.loadingStack.add(modelLocation); synchronized(this) {
UnbakedModel iunbakedmodel = missingModel; if (this.loadingStack.contains(modelLocation)) {
throw new IllegalStateException("Circular reference while loading " + modelLocation);
} else {
this.loadingStack.add(modelLocation);
UnbakedModel iunbakedmodel = missingModel;
while(!this.loadingStack.isEmpty()) { while(!this.loadingStack.isEmpty()) {
ResourceLocation resourcelocation = this.loadingStack.iterator().next(); ResourceLocation resourcelocation = this.loadingStack.iterator().next();
try { try {
if (!this.unbakedCache.containsKey(resourcelocation)) { if (!this.unbakedCache.containsKey(resourcelocation)) {
if(debugDynamicModelLoading) if(debugDynamicModelLoading)
LOGGER.info("Loading {}", resourcelocation); LOGGER.info("Loading {}", resourcelocation);
this.loadModel(resourcelocation); this.loadModel(resourcelocation);
// TODO: in theory the cache can get evicted right here and we lose the model
// very unlikely to occur though
}
} catch (ModelBakery.BlockStateDefinitionException var9) {
LOGGER.warn(var9.getMessage());
this.unbakedCache.put(resourcelocation, iunbakedmodel);
} catch (Exception var10) {
LOGGER.warn("Unable to load model: '{}' referenced from: {}: {}", resourcelocation, modelLocation, var10);
this.unbakedCache.put(resourcelocation, iunbakedmodel);
} finally {
this.loadingStack.remove(resourcelocation);
}
} }
} catch (ModelBakery.BlockStateDefinitionException var9) {
LOGGER.warn(var9.getMessage()); return this.unbakedCache.getOrDefault(modelLocation, iunbakedmodel);
this.unbakedCache.put(resourcelocation, iunbakedmodel);
} catch (Exception var10) {
LOGGER.warn("Unable to load model: '{}' referenced from: {}: {}", resourcelocation, modelLocation, var10);
this.unbakedCache.put(resourcelocation, iunbakedmodel);
} finally {
this.loadingStack.remove(resourcelocation);
} }
} }
return this.unbakedCache.getOrDefault(modelLocation, iunbakedmodel);
} }
} }
@Overwrite @Overwrite
public synchronized BakedModel getBakedModel(ResourceLocation arg, ModelState arg2, Function<Material, TextureAtlasSprite> textureGetter) { public BakedModel getBakedModel(ResourceLocation arg, ModelState arg2, Function<Material, TextureAtlasSprite> textureGetter) {
Triple<ResourceLocation, Transformation, Boolean> triple = Triple.of(arg, arg2.getRotation(), arg2.isUvLocked()); Triple<ResourceLocation, Transformation, Boolean> triple = Triple.of(arg, arg2.getRotation(), arg2.isUvLocked());
if (this.bakedCache.containsKey(triple)) { BakedModel existing = this.bakedCache.get(triple);
return this.bakedCache.get(triple); if (existing != null) {
return existing;
} else if (this.atlasSet == null) { } else if (this.atlasSet == null) {
throw new IllegalStateException("bake called too early"); throw new IllegalStateException("bake called too early");
} else { } else {
if(debugDynamicModelLoading) synchronized (this) {
LOGGER.info("Baking {}", arg); if(debugDynamicModelLoading)
UnbakedModel iunbakedmodel = this.getModel(arg); LOGGER.info("Baking {}", arg);
iunbakedmodel.getMaterials(this::getModel, new HashSet<>()); UnbakedModel iunbakedmodel = this.getModel(arg);
BakedModel ibakedmodel = null; iunbakedmodel.getMaterials(this::getModel, new HashSet<>());
if (iunbakedmodel instanceof BlockModel) { BakedModel ibakedmodel = null;
BlockModel blockmodel = (BlockModel)iunbakedmodel; if (iunbakedmodel instanceof BlockModel) {
if (blockmodel.getRootModel() == GENERATION_MARKER) { BlockModel blockmodel = (BlockModel)iunbakedmodel;
ibakedmodel = ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBakery)(Object)this, blockmodel, this.atlasSet::getSprite, arg2, arg, false); if (blockmodel.getRootModel() == GENERATION_MARKER) {
ibakedmodel = ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBakery)(Object)this, blockmodel, this.atlasSet::getSprite, arg2, arg, false);
}
} }
if(ibakedmodel == null) {
ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg);
}
DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this);
ModLoader.get().postEvent(event);
this.bakedCache.put(triple, event.getModel());
return event.getModel();
} }
if(ibakedmodel == null) {
ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg);
}
DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this);
ModLoader.get().postEvent(event);
this.bakedCache.put(triple, event.getModel());
return event.getModel();
} }
} }
} }