Fix structure config not applying in every case (#1495)

* Fix structure config not applying in every case

* Make tempmap immutable

* delete unfinished sentence

oop

* Some more cleanup
This was done at the request of Technician

* Update fabric-structure-api-v1/src/main/resources/fabric.mod.json

Co-authored-by: liach <7806504+liach@users.noreply.github.com>

Co-authored-by: liach <7806504+liach@users.noreply.github.com>
This commit is contained in:
frqnny 2021-06-14 17:58:00 -04:00 committed by GitHub
parent 155f865cd1
commit 98295c3114
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 66 additions and 226 deletions

View file

@ -1,2 +1,6 @@
archivesBaseName = "fabric-structure-api-v1"
version = getSubprojectVersion(project, "1.1.10")
moduleDependencies(project, [
'fabric-lifecycle-events-v1',
'fabric-api-base'
])

View file

@ -16,31 +16,21 @@
package net.fabricmc.fabric.api.structure.v1;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.util.Identifier;
import net.minecraft.world.gen.chunk.StructureConfig;
import net.minecraft.world.gen.chunk.StructuresConfig;
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
import net.minecraft.world.gen.feature.FeatureConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import net.fabricmc.fabric.impl.structure.FabricStructureUtil;
import net.fabricmc.fabric.impl.structure.StructuresConfigHooks;
import net.fabricmc.fabric.mixin.structure.BiomeAccessor;
import net.fabricmc.fabric.impl.structure.FabricStructureImpl;
import net.fabricmc.fabric.mixin.structure.FlatChunkGeneratorConfigAccessor;
import net.fabricmc.fabric.mixin.structure.StructureFeatureAccessor;
import net.fabricmc.fabric.mixin.structure.StructuresConfigAccessor;
/**
* A builder for registering custom structures.
@ -182,10 +172,7 @@ public final class FabricStructureBuilder<FC extends FeatureConfig, S extends St
throw new IllegalStateException(String.format("Structure \"%s\" has mismatching name \"%s\". Structures should not override \"getName\".", id, structure.getName()));
}
StructuresConfigAccessor.setDefaultStructures(ImmutableMap.<StructureFeature<?>, StructureConfig>builder()
.putAll(StructuresConfig.DEFAULT_STRUCTURES)
.put(structure, defaultConfig)
.build());
FabricStructureImpl.STRUCTURE_TO_CONFIG_MAP.put(structure, defaultConfig);
if (superflatFeature != null) {
FlatChunkGeneratorConfigAccessor.getStructureToFeatures().put(structure, superflatFeature);
@ -198,31 +185,6 @@ public final class FabricStructureBuilder<FC extends FeatureConfig, S extends St
.build());
}
// update existing structures configs
for (StructuresConfig structuresConfig : FabricStructureUtil.DEFAULT_STRUCTURES_CONFIGS) {
((StructuresConfigHooks) structuresConfig).fabric_updateDefaultEntries();
}
// update builtin biomes, just to be safe
for (Biome biome : BuiltinRegistries.BIOME) {
BiomeAccessor biomeAccessor = (BiomeAccessor) (Object) biome;
Map<Integer, List<StructureFeature<?>>> structureLists = biomeAccessor.getStructureLists();
if (!(structureLists instanceof HashMap)) {
// not guaranteed by the standard to be a mutable map
((BiomeAccessor) (Object) biome).setStructureLists(structureLists = new HashMap<>(structureLists));
}
// not guaranteed by the standard to be mutable lists
structureLists.compute(step.ordinal(), (k, v) -> makeMutable(v)).add(structure);
}
return structure;
}
private static List<StructureFeature<?>> makeMutable(List<StructureFeature<?>> mapValue) {
if (mapValue == null) return new ArrayList<>();
if (!(mapValue instanceof ArrayList)) return new ArrayList<>(mapValue);
return mapValue;
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.structure;
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import net.minecraft.world.gen.chunk.StructureConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.fabricmc.fabric.mixin.structure.StructuresConfigAccessor;
public class FabricStructureImpl implements ModInitializer {
//Keeps a map of structures to structure configs.
public static final Map<StructureFeature<?>, StructureConfig> STRUCTURE_TO_CONFIG_MAP = new HashMap<>();
@Override
public void onInitialize() {
ServerWorldEvents.LOAD.register((server, world) -> {
// Need temp map as some mods use custom chunk generators with immutable maps in themselves.
Map<StructureFeature<?>, StructureConfig> tempMap = new HashMap<>(world.getChunkManager().getChunkGenerator().getStructuresConfig().getStructures());
tempMap.putAll(STRUCTURE_TO_CONFIG_MAP);
//Make it immutable again
ImmutableMap<StructureFeature<?>, StructureConfig> immutableMap = ImmutableMap.copyOf(tempMap);
((StructuresConfigAccessor) world.getChunkManager().getChunkGenerator().getStructuresConfig()).setStructures(immutableMap);
});
}
}

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.structure;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import net.minecraft.world.gen.chunk.StructuresConfig;
public final class FabricStructureUtil {
private FabricStructureUtil() { }
// This tracks all StructuresConfig objects that have been created with the default set of structures
// in order to add mod-created structures that are registered later
public static final Set<StructuresConfig> DEFAULT_STRUCTURES_CONFIGS = Collections.newSetFromMap(new WeakHashMap<>());
}

View file

@ -1,21 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.structure;
public interface StructuresConfigHooks {
void fabric_updateDefaultEntries();
}

View file

@ -1,37 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.structure;
import java.util.List;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.StructureFeature;
@Mixin(Biome.class)
public interface BiomeAccessor {
@Accessor("structures")
Map<Integer, List<StructureFeature<?>>> getStructureLists();
@Mutable
@Accessor("structures")
void setStructureLists(Map<Integer, List<StructureFeature<?>>> field_26634);
}

View file

@ -1,34 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.structure;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import net.fabricmc.fabric.impl.structure.FabricStructureUtil;
@Mixin(ChunkGeneratorSettings.class)
public class MixinChunkGeneratorSettings {
@Inject(method = "createUndergroundSettings", at = @At("RETURN"))
private static void onCreateCavesType(CallbackInfoReturnable<ChunkGeneratorSettings> cir) {
FabricStructureUtil.DEFAULT_STRUCTURES_CONFIGS.add(cir.getReturnValue().getStructuresConfig());
}
}

View file

@ -1,53 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.structure;
import java.util.Map;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
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 net.minecraft.world.gen.chunk.StructureConfig;
import net.minecraft.world.gen.chunk.StructuresConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import net.fabricmc.fabric.impl.structure.FabricStructureUtil;
import net.fabricmc.fabric.impl.structure.StructuresConfigHooks;
@Mixin(StructuresConfig.class)
public class MixinStructuresConfig implements StructuresConfigHooks {
@Shadow
@Final
private Map<StructureFeature<?>, StructureConfig> structures;
// This constructor of StructuresConfig initializes it with the default set of structures.
// Since a mod can register its structures later, we need to keep track of the object created
// here, so that we can add new structures to it later.
@Inject(method = "<init>(Z)V", at = @At("RETURN"))
private void onDefaultInit(CallbackInfo ci) {
FabricStructureUtil.DEFAULT_STRUCTURES_CONFIGS.add((StructuresConfig) (Object) this);
}
@Override
public void fabric_updateDefaultEntries() {
StructuresConfig.DEFAULT_STRUCTURES.forEach(structures::putIfAbsent);
}
}

View file

@ -16,7 +16,8 @@
package net.fabricmc.fabric.mixin.structure;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@ -28,8 +29,6 @@ import net.minecraft.world.gen.feature.StructureFeature;
@Mixin(StructuresConfig.class)
public interface StructuresConfigAccessor {
@Mutable
@Accessor("DEFAULT_STRUCTURES")
static void setDefaultStructures(ImmutableMap<StructureFeature<?>, StructureConfig> defaultStructures) {
throw new AssertionError("Untransformed accessor");
}
@Accessor("structures")
void setStructures(Map<StructureFeature<?>, StructureConfig> structures);
}

View file

@ -3,11 +3,8 @@
"package": "net.fabricmc.fabric.mixin.structure",
"compatibilityLevel": "JAVA_16",
"mixins": [
"BiomeAccessor",
"ChunkSerializerMixin",
"FlatChunkGeneratorConfigAccessor",
"MixinChunkGeneratorSettings",
"MixinStructuresConfig",
"StructureFeatureAccessor",
"StructuresConfigAccessor"
],

View file

@ -15,9 +15,15 @@
"authors": [
"FabricMC"
],
"entrypoints": {
"main": [
"net.fabricmc.fabric.impl.structure.FabricStructureImpl"
]
},
"depends": {
"fabricloader": ">=0.8.0",
"fabric-api-base": "*"
"fabric-api-base": "*",
"fabric-lifecycle-events-v1": ">=1.4.4"
},
"description": "Hooks for registering custom structures.",
"mixins": [