Skip to content

Commit 689b272

Browse files
committed
Add a level screen provider registry
1 parent e1e5711 commit 689b272

File tree

12 files changed

+526
-0
lines changed

12 files changed

+526
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.api.client.screen.v1;
18+
19+
import java.util.Objects;
20+
import java.util.Optional;
21+
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
25+
import net.minecraft.client.gui.screen.world.LevelScreenProvider;
26+
import net.minecraft.registry.RegistryKey;
27+
import net.minecraft.world.gen.WorldPreset;
28+
29+
import net.fabricmc.fabric.mixin.screen.LevelScreenProviderAccessor;
30+
31+
/**
32+
* Adds registration hooks for {@link LevelScreenProvider}s.
33+
*/
34+
public final class LevelScreenProviderRegistry {
35+
private static final Logger LOGGER = LoggerFactory.getLogger(LevelScreenProviderRegistry.class);
36+
37+
private LevelScreenProviderRegistry() {
38+
}
39+
40+
/**
41+
* Registers a provider for a screen that allows users to adjust the generation options for a given world preset.
42+
*
43+
* @param worldPreset the world preset to register the provider for
44+
* @param provider the provider for the screen
45+
*/
46+
public static void register(RegistryKey<WorldPreset> worldPreset, LevelScreenProvider provider) {
47+
Objects.requireNonNull(worldPreset, "world preset cannot be null");
48+
Objects.requireNonNull(provider, "level screen provider cannot be null");
49+
50+
Optional<RegistryKey<WorldPreset>> key = Optional.of(worldPreset);
51+
LevelScreenProvider old = LevelScreenProviderAccessor.fabric_getWorldPresetToScreenProvider().put(key, provider);
52+
53+
if (old != null) {
54+
LOGGER.debug("Replaced old level screen provider mapping from {} to {} with {}", worldPreset, old, provider);
55+
}
56+
}
57+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.mixin.screen;
18+
19+
import java.util.Map;
20+
import java.util.Optional;
21+
22+
import org.spongepowered.asm.mixin.Mixin;
23+
import org.spongepowered.asm.mixin.gen.Accessor;
24+
25+
import net.minecraft.client.gui.screen.world.LevelScreenProvider;
26+
import net.minecraft.registry.RegistryKey;
27+
import net.minecraft.world.gen.WorldPreset;
28+
29+
@Mixin(LevelScreenProvider.class)
30+
public interface LevelScreenProviderAccessor {
31+
@Accessor("WORLD_PRESET_TO_SCREEN_PROVIDER")
32+
static Map<Optional<RegistryKey<WorldPreset>>, LevelScreenProvider> fabric_getWorldPresetToScreenProvider() {
33+
throw new AssertionError("Untransformed @Accessor");
34+
}
35+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.mixin.screen;
18+
19+
import java.util.HashMap;
20+
import java.util.Map;
21+
import java.util.Optional;
22+
23+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
24+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
25+
import org.spongepowered.asm.mixin.Mixin;
26+
import org.spongepowered.asm.mixin.injection.At;
27+
28+
import net.minecraft.client.gui.screen.world.LevelScreenProvider;
29+
import net.minecraft.registry.RegistryKey;
30+
import net.minecraft.world.gen.WorldPreset;
31+
32+
@Mixin(LevelScreenProvider.class)
33+
public interface LevelScreenProviderMixin {
34+
@WrapOperation(method = "<clinit>", at = @At(value = "INVOKE", target = "Ljava/util/Map;of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/Map;"))
35+
private static Map<Optional<RegistryKey<WorldPreset>>, LevelScreenProvider> makeMutable(Object k1, Object v1, Object k2, Object v2, Operation<Map<Optional<RegistryKey<WorldPreset>>, LevelScreenProvider>> operation) {
36+
return new HashMap<>(operation.call(k1, v1, k2, v2));
37+
}
38+
}

fabric-screen-api-v1/src/client/resources/fabric-screen-api-v1.mixins.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"client": [
66
"GameRendererMixin",
77
"HandledScreenMixin",
8+
"LevelScreenProviderAccessor",
9+
"LevelScreenProviderMixin",
810
"MinecraftClientMixin",
911
"ScreenMixin"
1012
],
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.test.screen;
18+
19+
import java.util.function.BiFunction;
20+
import java.util.function.Function;
21+
22+
import net.minecraft.block.BlockState;
23+
import net.minecraft.client.gui.DrawContext;
24+
import net.minecraft.client.gui.screen.Screen;
25+
import net.minecraft.client.gui.screen.world.CreateWorldScreen;
26+
import net.minecraft.client.gui.widget.ButtonWidget;
27+
import net.minecraft.client.world.GeneratorOptionsHolder;
28+
import net.minecraft.registry.Registries;
29+
import net.minecraft.registry.Registry;
30+
import net.minecraft.registry.RegistryKeys;
31+
import net.minecraft.screen.ScreenTexts;
32+
import net.minecraft.text.Text;
33+
import net.minecraft.util.math.random.Random;
34+
import net.minecraft.world.biome.Biome;
35+
import net.minecraft.world.gen.chunk.ChunkGenerator;
36+
37+
import net.fabricmc.fabric.test.screen.chunk.FabriclandChunkGenerator;
38+
import net.fabricmc.fabric.test.screen.chunk.FabriclandChunkGeneratorConfig;
39+
40+
public class FabriclandScreen extends Screen {
41+
private static final Text TITLE = Text.literal("Fabricland");
42+
43+
private static final int BUTTON_WIDTH = 150;
44+
private static final int LARGE_BUTTON_WIDTH = 210;
45+
private static final int BUTTON_HEIGHT = 20;
46+
47+
private final CreateWorldScreen parent;
48+
private final Random random = Random.create();
49+
50+
private FabriclandChunkGeneratorConfig config;
51+
52+
public FabriclandScreen(CreateWorldScreen parent, GeneratorOptionsHolder generatorOptionsHolder) {
53+
super(TITLE);
54+
this.parent = parent;
55+
56+
ChunkGenerator chunkGenerator = generatorOptionsHolder.selectedDimensions().getChunkGenerator();
57+
this.config = FabriclandChunkGeneratorConfig.from(chunkGenerator);
58+
}
59+
60+
@Override
61+
protected void init() {
62+
int x = (this.width - LARGE_BUTTON_WIDTH) / 2;
63+
64+
this.addDrawableChild(createChangeBlockButton("outline", FabriclandChunkGeneratorConfig::outline, (config, outline) -> config.withOutline(outline)).dimensions(x, 80, LARGE_BUTTON_WIDTH, BUTTON_HEIGHT).build());
65+
this.addDrawableChild(createChangeBlockButton("background", FabriclandChunkGeneratorConfig::background, (config, background) -> config.withBackground(background)).dimensions(x, 105, LARGE_BUTTON_WIDTH, BUTTON_HEIGHT).build());
66+
67+
this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, button -> {
68+
this.parent.getWorldCreator().applyModifier((dynamicRegistryManager, dimensionsRegistryHolder) -> {
69+
Registry<Biome> biomeRegistry = dynamicRegistryManager.getOrThrow(RegistryKeys.BIOME);
70+
ChunkGenerator chunkGenerator = new FabriclandChunkGenerator(biomeRegistry, config);
71+
72+
return dimensionsRegistryHolder.with(dynamicRegistryManager, chunkGenerator);
73+
});
74+
75+
this.client.setScreen(this.parent);
76+
}).dimensions((this.width - BUTTON_WIDTH) / 2, this.height - 28, BUTTON_WIDTH, BUTTON_HEIGHT).build());
77+
}
78+
79+
@Override
80+
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
81+
super.render(context, mouseX, mouseY, delta);
82+
context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 8, 0xFFFFFF);
83+
}
84+
85+
@Override
86+
public void close() {
87+
this.client.setScreen(this.parent);
88+
}
89+
90+
private ButtonWidget.Builder createChangeBlockButton(String suffix, Function<FabriclandChunkGeneratorConfig, BlockState> getter, BiFunction<FabriclandChunkGeneratorConfig, BlockState, FabriclandChunkGeneratorConfig> setter) {
91+
Text title = getChangeBlockButtonMessage(suffix, getter.apply(this.config));
92+
93+
return ButtonWidget.builder(title, button -> {
94+
Registries.BLOCK.getRandom(this.random).ifPresent(entry -> {
95+
BlockState next = entry.value().getDefaultState();
96+
97+
this.config = setter.apply(this.config, next);
98+
button.setMessage(getChangeBlockButtonMessage(suffix, next));
99+
});
100+
});
101+
}
102+
103+
private static Text getChangeBlockButtonMessage(String suffix, BlockState state) {
104+
return Text.translatable("generator.fabric-screen-api-v1-testmod.fabricland." + suffix, state.getBlock().getName());
105+
}
106+
}

fabric-screen-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/screen/ScreenTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,30 @@
2828
import net.minecraft.client.gui.widget.ButtonWidget;
2929
import net.minecraft.client.gui.widget.ClickableWidget;
3030
import net.minecraft.client.render.RenderLayer;
31+
import net.minecraft.registry.Registries;
32+
import net.minecraft.registry.Registry;
33+
import net.minecraft.registry.RegistryKey;
34+
import net.minecraft.registry.RegistryKeys;
3135
import net.minecraft.text.Text;
3236
import net.minecraft.util.Identifier;
37+
import net.minecraft.world.gen.WorldPreset;
3338

3439
import net.fabricmc.api.ClientModInitializer;
40+
import net.fabricmc.fabric.api.client.screen.v1.LevelScreenProviderRegistry;
3541
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
3642
import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
3743
import net.fabricmc.fabric.api.client.screen.v1.Screens;
44+
import net.fabricmc.fabric.test.screen.chunk.FabriclandChunkGenerator;
3845

3946
public final class ScreenTests implements ClientModInitializer {
47+
public static final String MOD_ID = "fabric-screen-api-v1-testmod";
48+
4049
public static final Identifier ARMOR_FULL_TEXTURE = Identifier.ofVanilla("hud/armor_full");
4150
private static final Logger LOGGER = LoggerFactory.getLogger("FabricScreenApiTests");
4251

52+
public static final Identifier FABRICLAND_ID = id("fabricland");
53+
public static final RegistryKey<WorldPreset> FABRICLAND_WORLD_PRESET = RegistryKey.of(RegistryKeys.WORLD_PRESET, FABRICLAND_ID);
54+
4355
@Override
4456
public void onInitializeClient() {
4557
LOGGER.info("Started Screen Testmod");
@@ -48,6 +60,12 @@ public void onInitializeClient() {
4860
});
4961

5062
ScreenEvents.AFTER_INIT.register(this::afterInitScreen);
63+
64+
Registry.register(Registries.CHUNK_GENERATOR, FABRICLAND_ID, FabriclandChunkGenerator.CODEC);
65+
LevelScreenProviderRegistry.register(FABRICLAND_WORLD_PRESET, (parent, generatorOptionsHolder) -> {
66+
LOGGER.info("Provided level screen provider for Fabricland");
67+
return new FabriclandScreen(parent, generatorOptionsHolder);
68+
});
5169
}
5270

5371
private void afterInitScreen(MinecraftClient client, Screen screen, int windowWidth, int windowHeight) {
@@ -96,6 +114,10 @@ private void afterInitScreen(MinecraftClient client, Screen screen, int windowWi
96114
}
97115
}
98116

117+
public static Identifier id(String name) {
118+
return Identifier.of(MOD_ID, name);
119+
}
120+
99121
// Test that mouseReleased is called
100122
private static final class TestButtonWidget extends ButtonWidget {
101123
private TestButtonWidget() {

0 commit comments

Comments
 (0)