Skip to content

Commit

Permalink
added a vanilla mods toggle, added block error screen, fixed CosmicRe…
Browse files Browse the repository at this point in the history
…achFont, improved broken data mods error reporting
  • Loading branch information
Nanobass committed Jun 24, 2024
1 parent abf50c5 commit 9baa073
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 39 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Mod Properties
id = fluxapi
version = 0.7.2
version = 0.7.3
flux_desc = The central modding API for Cosmic Reach Fabric/Quilt

group = dev.crmodders
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/dev/crmodders/flux/block/DataModBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static class JsonBlock {
public LinkedHashMap<String, ?> blockEntityParams;
}

public ResourceLocation debugResourceLocation;
public String blockJson;
public String blockName;

Expand All @@ -31,6 +32,7 @@ public DataModBlock(String blockName) {

public DataModBlock(String blockName, ResourceLocation json) {
this(blockName, json.locate().readString());
this.debugResourceLocation = json;
}

public DataModBlock(String blockName, String blockJson) {
Expand Down
137 changes: 137 additions & 0 deletions src/main/java/dev/crmodders/flux/engine/BlockErrorScreen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package dev.crmodders.flux.engine;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import dev.crmodders.flux.block.DataModBlock;
import dev.crmodders.flux.engine.blocks.BlockLoadException;
import dev.crmodders.flux.engine.blocks.BlockLoader;
import dev.crmodders.flux.ui.CosmicReachFont;
import finalforeach.cosmicreach.gamestates.GameState;
import finalforeach.cosmicreach.io.SaveLocation;
import finalforeach.cosmicreach.ui.UIElement;
import finalforeach.cosmicreach.ui.VerticalAnchor;
import org.lwjgl.opengl.GL11;

import java.io.PrintWriter;
import java.io.StringWriter;

public class BlockErrorScreen extends GameState {

public Stage gdxStage;
public OrthographicCamera gdxStageCamera;
public Viewport gdxStageViewport;
protected Color background = Color.BLACK;

private final BlockLoader blockLoader;
private final GameState next;

private ScrollPane scrollPane;

public BlockErrorScreen(BlockLoader blockLoader, GameState next) {
this.blockLoader = blockLoader;
this.next = next;
}

@Override
public void create() {
super.create();
gdxStageCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
gdxStageViewport = new ExtendViewport(800.0F, 600.0F, gdxStageCamera);
gdxStage = new Stage(gdxStageViewport, batch);
Gdx.input.setInputProcessor(gdxStage);
gdxStageCamera.position.set(0, 0, 0);
gdxStageViewport.apply(false);

Label title = new Label("Error while loading Blocks", new Label.LabelStyle(CosmicReachFont.FONT_BIG, Color.WHITE));
title.layout();
title.setSize(title.getGlyphLayout().width, title.getGlyphLayout().height);
title.setPosition(0.0F, 250.0F, Align.center);
gdxStage.addActor(title);

StringBuilder errorText = new StringBuilder();

for(BlockLoadException error : blockLoader.errors) {

StringWriter writer = new StringWriter();
error.getCause().printStackTrace(new PrintWriter(writer));
String exception = writer.toString();

String className = error.iModBlock != null ? error.iModBlock.getClass().getSimpleName() : "Unknown";
String fileName = error.iModBlock instanceof DataModBlock dataModBlock && dataModBlock.debugResourceLocation != null ? dataModBlock.debugResourceLocation.locate().name() : "Unknown";
String blockName = error.blockName != null ? error.blockName : "Unknown";
String blockId = error.blockId != null ? error.blockId.toString() : "Unknown";

errorText
.append("Error while loading Block (Class: ").append(className)
.append(", File: \"").append(fileName)
.append(", Name: \"").append(blockName)
.append("\", Id: \"").append(blockId)
.append("\")\n")
.append("\nError Stacktrace:\n");
for(String line : exception.lines().toList()) {
errorText.append(" ").append(line).append("\n");
}
errorText.append("\n\n");

}

// don't waste memory
blockLoader.errors.clear();

try {
FileHandle errorFile = Gdx.files.absolute(SaveLocation.getSaveFolderLocation() + "/flux-error-latest.txt");
errorFile.writeString(errorText.toString(), false);
} catch (Exception ignored) {}

Label error = new Label("\n" + errorText, new Label.LabelStyle(CosmicReachFont.FONT, Color.WHITE));
error.setWrap(true);
error.invalidate();
error.pack();
error.layout();

scrollPane = new ScrollPane(error);
scrollPane.setSize(800.0F, 450.0F);
scrollPane.setPosition(0, 0, Align.center);
scrollPane.setScrollbarsVisible(true);
scrollPane.layout();
gdxStage.addActor(scrollPane);

UIElement returnButton = new UIElement(0.0F, -16.0F, 250.0F, 50.0F) {
public void onClick() {
super.onClick();
GameState.switchToGameState(next);
}
};
returnButton.vAnchor = VerticalAnchor.BOTTOM_ALIGNED;
returnButton.setText("Continue");
returnButton.show();
uiObjects.add(returnButton);
}

@Override
public void render() {
super.render();
Gdx.gl.glClearColor(background.r, background.g, background.b, background.a);
Gdx.gl.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
gdxStageViewport.apply(false);
gdxStage.act();
gdxStage.draw();
drawUIElements();
}

@Override
public void resize(int width, int height) {
super.resize(width, height);
gdxStageViewport.update(width, height, false);
}


}
5 changes: 4 additions & 1 deletion src/main/java/dev/crmodders/flux/engine/GameLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,10 @@ public void render() {
}

if(FluxConstants.FluxHasLoaded) {
GameState.switchToGameState(new PrealphaPreamble());
if(blockLoader.errors.isEmpty())
switchToGameState(new PrealphaPreamble());
else
switchToGameState(new BlockErrorScreen(blockLoader, new PrealphaPreamble()));
}

super.render();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
package dev.crmodders.flux.engine.blocks;

import dev.crmodders.flux.block.IModBlock;
import dev.crmodders.flux.tags.Identifier;
import finalforeach.cosmicreach.blocks.Block;

public class BlockLoadException extends RuntimeException {

public final IModBlock iModBlock;
public final String blockName;
public final Identifier blockId;
public final String json;
public final Block block;

public BlockLoadException(String blockName, Throwable cause) {
public BlockLoadException(IModBlock iModBlock, String blockName, Identifier blockId, String json, Block block, Throwable cause) {
super(cause);
this.iModBlock = iModBlock;
this.blockName = blockName;
this.blockId = blockId;
this.json = json;
this.block = block;
}

}
72 changes: 46 additions & 26 deletions src/main/java/dev/crmodders/flux/engine/blocks/BlockLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
Expand All @@ -28,6 +29,8 @@
public class BlockLoader {

public BlockModelFactory factory = new BlockModelFactory();
public Json json = new Json();
public List<BlockLoadException> errors = new ArrayList<>();

/**
* Call this method to register custom json models, this has to be called
Expand Down Expand Up @@ -91,37 +94,52 @@ public void registerEventAction(Identifier actionId, IFactory<FluxBlockAction> a
* @return the block id extracted from the generated json
*/
public Identifier loadBlock(IModBlock modBlock) {
Json json = new Json();

BlockGenerator blockGenerator = modBlock.getBlockGenerator();
blockGenerator.register(this);
String blockJson = blockGenerator.generateJson();
Block block = json.fromJson(Block.class, blockJson);

for(BlockModelGenerator modelGenerator : modBlock.getBlockModelGenerators(blockGenerator.blockId)) {
modelGenerator.register(this);
String modelName = modelGenerator.getModelName();
int rotXZ = 0;
String modelJson = modelGenerator.generateJson();
registerBlockModel(modelName, rotXZ, modelJson);
BlockGenerator blockGenerator;
try {
blockGenerator = modBlock.getBlockGenerator();
} catch (Exception e) {
throw new BlockLoadException(modBlock, null, null, null, null, e);
}

List<BlockEventGenerator> eventGenerators = modBlock.getBlockEventGenerators(blockGenerator.blockId);
if(eventGenerators.isEmpty()) {
BlockEventGenerator eventGenerator = new BlockEventGenerator(blockGenerator.blockId, "flux_default");
eventGenerators = List.of(eventGenerator);
String blockJson;
try {
blockGenerator.register(this);
blockJson = blockGenerator.generateJson();
} catch (Exception e) {
throw new BlockLoadException(modBlock, blockGenerator.blockName, blockGenerator.blockId, null, null, e);
}
for(BlockEventGenerator eventGenerator : eventGenerators) {
eventGenerator.createTrigger("onInteract", Identifier.fromString("fluxapi:mod_block_interact"), Map.of("blockId", blockGenerator.blockId));
eventGenerator.createTrigger("onPlace", Identifier.fromString("fluxapi:mod_block_place"), Map.of("blockId", blockGenerator.blockId));
eventGenerator.createTrigger("onBreak", Identifier.fromString("fluxapi:mod_block_break"), Map.of("blockId", blockGenerator.blockId));
eventGenerator.register(this);
String eventName = eventGenerator.getEventName();
String eventJson = eventGenerator.generateJson();
registerEvent(eventName, eventJson);

Block block;
try {
block = json.fromJson(Block.class, blockJson);
} catch (Exception e) {
throw new BlockLoadException(modBlock, blockGenerator.blockName, blockGenerator.blockId, blockJson, null, e);
}

try {
for(BlockModelGenerator modelGenerator : modBlock.getBlockModelGenerators(blockGenerator.blockId)) {
modelGenerator.register(this);
String modelName = modelGenerator.getModelName();
int rotXZ = 0;
String modelJson = modelGenerator.generateJson();
registerBlockModel(modelName, rotXZ, modelJson);
}

List<BlockEventGenerator> eventGenerators = modBlock.getBlockEventGenerators(blockGenerator.blockId);
if(eventGenerators.isEmpty()) {
BlockEventGenerator eventGenerator = new BlockEventGenerator(blockGenerator.blockId, "flux_default");
eventGenerators = List.of(eventGenerator);
}
for(BlockEventGenerator eventGenerator : eventGenerators) {
eventGenerator.createTrigger("onInteract", Identifier.fromString("fluxapi:mod_block_interact"), Map.of("blockId", blockGenerator.blockId));
eventGenerator.createTrigger("onPlace", Identifier.fromString("fluxapi:mod_block_place"), Map.of("blockId", blockGenerator.blockId));
eventGenerator.createTrigger("onBreak", Identifier.fromString("fluxapi:mod_block_break"), Map.of("blockId", blockGenerator.blockId));
eventGenerator.register(this);
String eventName = eventGenerator.getEventName();
String eventJson = eventGenerator.generateJson();
registerEvent(eventName, eventJson);
}

for (String stateKey : block.blockStates.keys().toArray()) {
BlockState blockState = block.blockStates.get(stateKey);
blockState.stringId = stateKey;
Expand All @@ -135,7 +153,9 @@ public Identifier loadBlock(IModBlock modBlock) {
Block.allBlockStates.remove(blockState.stringId);
}
Block.allBlocks.removeValue(block, true);
throw new BlockLoadException(blockGenerator.blockName, e);
Block.blocksByStringId.remove(blockGenerator.blockId.toString());
Block.blocksByName.remove(blockGenerator.blockName);
throw new BlockLoadException(modBlock, blockGenerator.blockName, blockGenerator.blockId, blockJson, block, e);
}
return blockGenerator.blockId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public void doStage() {
Identifier blockId = loader.blockLoader.loadBlock(block);
FluxRegistries.BLOCKS.register(blockId, block);
} catch (BlockLoadException e) {
LOGGER.warn("Cannot load block: \"{}\"", e.blockName, e.getCause());
LOGGER.error("Cannot load block: \"{}\"", e.blockName, e);
loader.blockLoader.errors.add(e);
}
}
FluxRegistries.BLOCKS.freeze();
Expand Down
22 changes: 14 additions & 8 deletions src/main/java/dev/crmodders/flux/ui/CosmicReachFont.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
public class CosmicReachFont {

public static final BitmapFont FONT = createCosmicReachFont();
public static final BitmapFont FONT_BIG = createCosmicReachFont();

static {
FONT_BIG.getData().setScale(2.5F);
}

public static BitmapFont createCosmicReachFont() {
List<FontTexture> fontTextures = new ArrayList<>();
Expand Down Expand Up @@ -71,20 +76,21 @@ public static BitmapFont createCosmicReachFont() {
for(int unicode = ft.unicodeStart; unicode < ft.unicodeStart + 256; unicode++) {
Vector2 charStart = ft.fontCharStartPos[unicode - ft.unicodeStart];
Vector2 charSize = ft.fontCharSizes[unicode - ft.unicodeStart];
TextureRegion textureRegion = ft.fontTextureRegions[unicode - ft.unicodeStart];
BitmapFont.Glyph glyph = new BitmapFont.Glyph();
glyph.id = unicode;
glyph.srcX = xOffset + (int)charStart.x;
glyph.srcY = yOffset + (int)charStart.y;
glyph.width = (int)charSize.x;
if(unicode == ' ')
glyph.width /= 4;
glyph.height = (int)charSize.y;
glyph.srcX = xOffset + (int) charStart.x;
glyph.srcY = yOffset + textureRegion.getRegionY() - textureRegion.getRegionHeight();
glyph.width = (int) charSize.x;
glyph.height = textureRegion.getRegionHeight();
glyph.xadvance = glyph.width + 2;
glyph.yoffset = 0;
data.setGlyph(unicode, glyph);
}
}

data.down = -data.getGlyph('\n').height;
BitmapFont.Glyph space = data.getGlyph(' ');
space.width /= 4;
space.xadvance = space.width;
return new BitmapFont(data, new TextureRegion(texture), true);
}

Expand Down

0 comments on commit 9baa073

Please sign in to comment.