Prepared BCLib Version warning screen
This commit is contained in:
parent
46a5603ff7
commit
4fc9c06204
7 changed files with 171 additions and 58 deletions
|
@ -6,6 +6,8 @@ import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.fabricmc.loader.api.ModContainer;
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.client.gui.screens.worldselection.EditWorldScreen;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
@ -14,12 +16,15 @@ import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||||
import ru.bclib.api.dataexchange.DataHandler;
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||||
|
import ru.bclib.gui.screens.ConfirmFixScreen;
|
||||||
|
import ru.bclib.gui.screens.WarnBCLibVersionMismatch;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class HelloClient extends DataHandler {
|
public class HelloClient extends DataHandler {
|
||||||
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_client"), HelloClient::new, true);
|
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_client"), HelloClient::new, true);
|
||||||
|
@ -86,7 +91,19 @@ public class HelloClient extends DataHandler {
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
protected void showBCLibError(Minecraft client){
|
protected void showBCLibError(Minecraft client){
|
||||||
BCLib.LOGGER.error("BCLib differs on client and server. Stopping.");
|
client.pauseGame(false);
|
||||||
client.stop();
|
BCLib.LOGGER.error("BCLib differs on client and server.");
|
||||||
|
client.setScreen(new WarnBCLibVersionMismatch((download) -> {
|
||||||
|
Minecraft.getInstance().setScreen((Screen)null);
|
||||||
|
if (download){
|
||||||
|
requestDownloads((hadErrors)->{
|
||||||
|
client.stop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestDownloads(Consumer<Boolean> whenFinished){
|
||||||
|
BCLib.LOGGER.warning("Starting download of BCLib");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,9 +227,6 @@ public class DataFixerAPI {
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
static void showBackupWarning(String levelID, Consumer<Boolean> whenFinished){
|
static void showBackupWarning(String levelID, Consumer<Boolean> whenFinished){
|
||||||
TranslatableComponent promptText = new TranslatableComponent("bclib.datafixer.backupWarning.prompt");
|
|
||||||
TranslatableComponent buttonTitle = new TranslatableComponent("bclib.datafixer.backupWarning.button");
|
|
||||||
|
|
||||||
Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, (createBackup, applyFixes) -> {
|
Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, (createBackup, applyFixes) -> {
|
||||||
if (createBackup) {
|
if (createBackup) {
|
||||||
EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID);
|
EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID);
|
||||||
|
@ -238,7 +235,6 @@ public class DataFixerAPI {
|
||||||
Minecraft.getInstance().setScreen((Screen)null);
|
Minecraft.getInstance().setScreen((Screen)null);
|
||||||
whenFinished.accept(applyFixes);
|
whenFinished.accept(applyFixes);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void runDataFixes(File dir, MigrationProfile profile, ProgressListener progress) {
|
private static void runDataFixes(File dir, MigrationProfile profile, ProgressListener progress) {
|
||||||
|
|
|
@ -5,9 +5,7 @@ import net.minecraft.client.gui.Font;
|
||||||
import net.minecraft.client.gui.components.Button;
|
import net.minecraft.client.gui.components.Button;
|
||||||
import net.minecraft.client.gui.components.Button.OnPress;
|
import net.minecraft.client.gui.components.Button.OnPress;
|
||||||
import net.minecraft.client.gui.components.MultiLineLabel;
|
import net.minecraft.client.gui.components.MultiLineLabel;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -27,72 +25,107 @@ public class GridLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ButtonPos {
|
class ButtonPos {
|
||||||
|
final int top;
|
||||||
final int height;
|
final int height;
|
||||||
final int width;
|
final int width;
|
||||||
final float alpha;
|
final float alpha;
|
||||||
final Component component;
|
final Component component;
|
||||||
final Button.OnPress onPress;
|
final Button.OnPress onPress;
|
||||||
|
|
||||||
ButtonPos(float alpha, int width, int height, Component component, OnPress onPress) {
|
ButtonPos(float alpha, int top, int width, int height, Component component, OnPress onPress) {
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
|
this.top = top;
|
||||||
this.alpha = alpha;
|
this.alpha = alpha;
|
||||||
this.component = component;
|
this.component = component;
|
||||||
this.onPress = onPress;
|
this.onPress = onPress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public final int width;
|
public final int width;
|
||||||
|
public final int height;
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Font font;
|
private final Font font;
|
||||||
private final Consumer<Button> addButtonFunction;
|
private final Consumer<Button> addButtonFunction;
|
||||||
public final int topStart;
|
private final int topStart;
|
||||||
|
private int topOffset;
|
||||||
private int top;
|
private int top;
|
||||||
private int currentRowHeight = 0;
|
private int currentRowHeight = 0;
|
||||||
|
private int currentRowMargin = 6;
|
||||||
|
private int lastRowMargin = 0;
|
||||||
|
|
||||||
final private List<LablePos> labels;
|
final private List<LablePos> labels;
|
||||||
final private List<ButtonPos> buttons;
|
final private List<List<ButtonPos>> buttons;
|
||||||
|
private List<ButtonPos> currentButtonRow;
|
||||||
|
|
||||||
public GridLayout(int topStart, int width, Font font, Consumer<Button> addButtonFunction){
|
public GridLayout(int topStart, int width, int height, Font font, Consumer<Button> addButtonFunction){
|
||||||
Objects.requireNonNull(font);
|
Objects.requireNonNull(font);
|
||||||
this.topStart = topStart;
|
this.topStart = topStart;
|
||||||
top = topStart + 20;
|
top = topStart + 20;
|
||||||
|
this.topOffset = 0;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
this.font = font;
|
this.font = font;
|
||||||
this.addButtonFunction = addButtonFunction;
|
this.addButtonFunction = addButtonFunction;
|
||||||
labels = new ArrayList<>(4);
|
labels = new ArrayList<>(4);
|
||||||
buttons = new ArrayList<>(8);
|
buttons = new ArrayList<>(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTopStart(){
|
||||||
|
return topStart + topOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessageRow(Component text, int padding){
|
||||||
|
addMessageRow(MultiLineLabel.create(this.font, text, this.width - 2*padding));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMessageRow(MultiLineLabel lb){
|
public void addMessageRow(MultiLineLabel lb){
|
||||||
final int LABEL_MARGIN_BOTTOM = 12;
|
|
||||||
labels.add(new LablePos(lb, top));
|
labels.add(new LablePos(lb, top));
|
||||||
int promptLines = lb.getLineCount() + 1;
|
int promptLines = lb.getLineCount() + 1;
|
||||||
int height = promptLines * 9;
|
int height = promptLines * 9;
|
||||||
|
|
||||||
currentRowHeight = height + LABEL_MARGIN_BOTTOM;;
|
currentRowMargin = 12;
|
||||||
|
currentRowHeight = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startRow(){
|
public void startRow(){
|
||||||
this.endRow();
|
this.endRow();
|
||||||
top += currentRowHeight;
|
this.currentButtonRow = new ArrayList<>(8);
|
||||||
currentRowHeight = 0;
|
this.buttons.add(this.currentButtonRow);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endRow(){
|
public void endRow(){
|
||||||
final int BUTTON_SPACING = 10;
|
lastRowMargin = currentRowMargin;
|
||||||
int count = buttons.size();
|
top += currentRowHeight + currentRowMargin;
|
||||||
int rowWidth = buttons.stream().map(b -> b.width).reduce(0, (p, c) -> p+c) + (count-1) * BUTTON_SPACING;
|
currentRowHeight = 0;
|
||||||
int left = (width-rowWidth)/2;
|
currentRowMargin = 0;
|
||||||
|
|
||||||
for (ButtonPos bp:buttons){
|
|
||||||
Button customButton = new Button(left, top, bp.width, bp.height, bp.component, bp.onPress);
|
|
||||||
customButton.setAlpha(bp.alpha);
|
|
||||||
addButtonFunction.accept(customButton);
|
|
||||||
|
|
||||||
left += BUTTON_SPACING + bp.width;
|
|
||||||
};
|
|
||||||
buttons.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void recenterVertically(){
|
||||||
|
int hg = (top - lastRowMargin) - topStart;
|
||||||
|
int targetTop = (height - hg)/2;
|
||||||
|
topOffset = targetTop - topStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void finalizeLayout(){
|
||||||
|
final int BUTTON_SPACING = 10;
|
||||||
|
for (List<ButtonPos> row : this.buttons) {
|
||||||
|
int count = row.size();
|
||||||
|
int rowWidth = row.stream()
|
||||||
|
.map(b -> b.width)
|
||||||
|
.reduce(0, (p, c) -> p + c) + (count - 1) * BUTTON_SPACING;
|
||||||
|
int left = (width - rowWidth) / 2;
|
||||||
|
|
||||||
|
for (ButtonPos bp : row) {
|
||||||
|
Button customButton = new Button(left, bp.top+topOffset, bp.width, bp.height, bp.component, bp.onPress);
|
||||||
|
customButton.setAlpha(bp.alpha);
|
||||||
|
addButtonFunction.accept(customButton);
|
||||||
|
|
||||||
|
left += BUTTON_SPACING + bp.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addButton(int width, int height, Component component, Button.OnPress onPress){
|
public void addButton(int width, int height, Component component, Button.OnPress onPress){
|
||||||
addButton(1.0f, width, height, component, onPress);
|
addButton(1.0f, width, height, component, onPress);
|
||||||
}
|
}
|
||||||
|
@ -108,15 +141,14 @@ public class GridLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addButton(float alpha, int width, int height, Component component, Button.OnPress onPress){
|
public void addButton(float alpha, int width, int height, Component component, Button.OnPress onPress){
|
||||||
final int BUTTON_MARGIN_BOTTOM = 6;
|
currentRowHeight = Math.max(currentRowHeight, height);
|
||||||
|
currentRowMargin = 6;
|
||||||
currentRowHeight = Math.max(currentRowHeight, height + BUTTON_MARGIN_BOTTOM);
|
currentButtonRow.add(new ButtonPos(alpha, top, width, height, component, onPress));
|
||||||
buttons.add(new ButtonPos(alpha, width, height, component, onPress));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(PoseStack poseStack){
|
public void render(PoseStack poseStack){
|
||||||
labels.forEach(lp -> {
|
labels.forEach(lp -> {
|
||||||
lp.label.renderCentered(poseStack, this.width / 2, lp.top);
|
lp.label.renderCentered(poseStack, this.width / 2, lp.top + topOffset);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
src/main/java/ru/bclib/gui/GridScreen.java
Normal file
34
src/main/java/ru/bclib/gui/GridScreen.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package ru.bclib.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public abstract class GridScreen extends Screen {
|
||||||
|
protected GridLayout grid = null;
|
||||||
|
public final int topStart;
|
||||||
|
|
||||||
|
public GridScreen(int topStart, Component title) {
|
||||||
|
super(title);
|
||||||
|
this.topStart = topStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected void init() {
|
||||||
|
super.init();
|
||||||
|
this.grid = new GridLayout(topStart, this.width, this.height, this.font, this::addRenderableWidget);
|
||||||
|
initLayout();
|
||||||
|
grid.finalizeLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void initLayout();
|
||||||
|
|
||||||
|
public void render(PoseStack poseStack, int i, int j, float f) {
|
||||||
|
this.renderBackground(poseStack);
|
||||||
|
drawCenteredString(poseStack, this.font, this.title, grid.width / 2, grid.getTopStart(), 16777215);
|
||||||
|
if (grid!=null) grid.render(poseStack);
|
||||||
|
super.render(poseStack, i, j, f);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,37 +14,30 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import ru.bclib.BCLib;
|
import ru.bclib.BCLib;
|
||||||
import ru.bclib.gui.GridLayout;
|
import ru.bclib.gui.GridLayout;
|
||||||
|
import ru.bclib.gui.GridScreen;
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
public class ConfirmFixScreen extends Screen {
|
public class ConfirmFixScreen extends GridScreen {
|
||||||
static final ResourceLocation BCLIB_LOGO_LOCATION = new ResourceLocation(BCLib.MOD_ID,
|
static final ResourceLocation BCLIB_LOGO_LOCATION = new ResourceLocation(BCLib.MOD_ID,
|
||||||
"icon.png");
|
"icon.png");
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Screen lastScreen;
|
private final Screen lastScreen;
|
||||||
protected final BackupConfirmScreen.Listener listener;
|
protected final ConfirmFixScreen.Listener listener;
|
||||||
private final Component description;
|
private final Component description;
|
||||||
private MultiLineLabel message;
|
|
||||||
protected int id;
|
protected int id;
|
||||||
private GridLayout grid = null;
|
|
||||||
|
|
||||||
public ConfirmFixScreen(@Nullable Screen screen, BackupConfirmScreen.Listener listener) {
|
public ConfirmFixScreen(@Nullable Screen screen, ConfirmFixScreen.Listener listener) {
|
||||||
super(new TranslatableComponent("bclib.datafixer.backupWarning.title"));
|
super(30, new TranslatableComponent("bclib.datafixer.backupWarning.title"));
|
||||||
this.message = MultiLineLabel.EMPTY;
|
|
||||||
this.lastScreen = screen;
|
this.lastScreen = screen;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
|
||||||
this.description = new TranslatableComponent("bclib.datafixer.backupWarning.message");
|
this.description = new TranslatableComponent("bclib.datafixer.backupWarning.message");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init() {
|
protected void initLayout() {
|
||||||
super.init();
|
|
||||||
this.grid = new GridLayout(30, this.width, this.font, this::addRenderableWidget);
|
|
||||||
|
|
||||||
final int BUTTON_WIDTH = 150;
|
|
||||||
final int BUTTON_SPACE = 10;
|
|
||||||
final int BUTTON_HEIGHT = 20;
|
final int BUTTON_HEIGHT = 20;
|
||||||
|
|
||||||
grid.addMessageRow(MultiLineLabel.create(this.font, this.description, this.width - 50));
|
grid.addMessageRow(this.description, 25);
|
||||||
|
|
||||||
grid.startRow();
|
grid.startRow();
|
||||||
grid.addButton( BUTTON_HEIGHT, new TranslatableComponent("bclib.datafixer.backupWarning.backup"), (button) -> {
|
grid.addButton( BUTTON_HEIGHT, new TranslatableComponent("bclib.datafixer.backupWarning.backup"), (button) -> {
|
||||||
|
@ -67,13 +60,6 @@ public class ConfirmFixScreen extends Screen {
|
||||||
grid.endRow();
|
grid.endRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(PoseStack poseStack, int i, int j, float f) {
|
|
||||||
this.renderBackground(poseStack);
|
|
||||||
drawCenteredString(poseStack, this.font, this.title, grid.width / 2, grid.topStart, 16777215);
|
|
||||||
if (grid!=null) grid.render(poseStack);
|
|
||||||
super.render(poseStack, i, j, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldCloseOnEsc() {
|
public boolean shouldCloseOnEsc() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -89,6 +75,6 @@ public class ConfirmFixScreen extends Screen {
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
void proceed(boolean bl, boolean bl2);
|
void proceed(boolean createBackup, boolean applyPatches);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package ru.bclib.gui.screens;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.network.chat.CommonComponents;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
|
import ru.bclib.gui.GridScreen;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class WarnBCLibVersionMismatch extends GridScreen {
|
||||||
|
private final Component description;
|
||||||
|
private final Listener listener;
|
||||||
|
public WarnBCLibVersionMismatch(Listener listener) {
|
||||||
|
super(30, new TranslatableComponent("bclib.datafixer.bclibmissmatch.title"));
|
||||||
|
|
||||||
|
this.description = new TranslatableComponent("bclib.datafixer.bclibmissmatch.message");
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initLayout() {
|
||||||
|
final int BUTTON_HEIGHT = 20;
|
||||||
|
|
||||||
|
grid.addMessageRow(this.description, 25);
|
||||||
|
|
||||||
|
grid.startRow();
|
||||||
|
grid.addButton( BUTTON_HEIGHT, CommonComponents.GUI_NO, (button) -> {
|
||||||
|
listener.proceed(false);
|
||||||
|
});
|
||||||
|
grid.addButton( BUTTON_HEIGHT, CommonComponents.GUI_YES, (button) -> {
|
||||||
|
listener.proceed(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
grid.endRow();
|
||||||
|
grid.recenterVertically();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldCloseOnEsc() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public interface Listener {
|
||||||
|
void proceed(boolean download);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,5 +4,7 @@
|
||||||
"bclib.datafixer.backupWarning.message": "The Guardian detected, that the internals of the following Mods did change since this world was last played.\n\nWe can automatically change the world for you. If you continue without applying the changes the world may not load correct. Before you continue, you should create a Backup.",
|
"bclib.datafixer.backupWarning.message": "The Guardian detected, that the internals of the following Mods did change since this world was last played.\n\nWe can automatically change the world for you. If you continue without applying the changes the world may not load correct. Before you continue, you should create a Backup.",
|
||||||
"bclib.datafixer.backupWarning.backup": "Create Backup and Continue",
|
"bclib.datafixer.backupWarning.backup": "Create Backup and Continue",
|
||||||
"bclib.datafixer.backupWarning.nofixes": "Continue Without Fixes",
|
"bclib.datafixer.backupWarning.nofixes": "Continue Without Fixes",
|
||||||
"bclib.datafixer.backupWarning.continue": "Continue Without Backup"
|
"bclib.datafixer.backupWarning.continue": "Continue Without Backup",
|
||||||
|
"bclib.datafixer.bclibmissmatch.title": "Version Mismatch",
|
||||||
|
"bclib.datafixer.bclibmissmatch.message": "The Version of BCLib on the server and this client do not match. This will cause problems when playing.\n\nDo you want to automatically download the BCLib-Version from the server. You will need to delete the old version from your Mods Directory and restart the game."
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue