mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
928 lines
30 KiB
Java
928 lines
30 KiB
Java
package net.torvald.terrarum;
|
|
|
|
import com.badlogic.gdx.ApplicationListener;
|
|
import com.badlogic.gdx.Files;
|
|
import com.badlogic.gdx.Gdx;
|
|
import com.badlogic.gdx.Screen;
|
|
import com.badlogic.gdx.audio.AudioDevice;
|
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
|
import com.badlogic.gdx.controllers.Controllers;
|
|
import com.badlogic.gdx.graphics.*;
|
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
|
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
|
import com.badlogic.gdx.utils.ScreenUtils;
|
|
import com.github.strikerx3.jxinput.XInputDevice;
|
|
import com.google.gson.JsonArray;
|
|
import com.google.gson.JsonObject;
|
|
import com.google.gson.JsonPrimitive;
|
|
import net.torvald.util.ArrayListMap;
|
|
import net.torvald.getcpuname.GetCpuName;
|
|
import net.torvald.terrarum.blockstats.MinimapComposer;
|
|
import net.torvald.terrarum.controller.GdxControllerAdapter;
|
|
import net.torvald.terrarum.controller.TerrarumController;
|
|
import net.torvald.terrarum.controller.XinputControllerAdapter;
|
|
import net.torvald.terrarum.gamecontroller.KeyToggler;
|
|
import net.torvald.terrarum.imagefont.TinyAlphNum;
|
|
import net.torvald.terrarum.modulebasegame.Ingame;
|
|
import net.torvald.terrarum.modulebasegame.IngameRenderer;
|
|
import net.torvald.terrarum.utils.JsonFetcher;
|
|
import net.torvald.terrarum.utils.JsonWriter;
|
|
import net.torvald.terrarum.worlddrawer.BlocksDrawer;
|
|
import net.torvald.terrarum.worlddrawer.LightmapRenderer;
|
|
import net.torvald.terrarumsansbitmap.gdx.GameFontBase;
|
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.Arrays;
|
|
import java.util.Random;
|
|
|
|
import static net.torvald.terrarum.TerrarumKt.gdxClearAndSetBlend;
|
|
|
|
/**
|
|
* The framework's Application Loader
|
|
*
|
|
*
|
|
* Created by minjaesong on 2017-08-01.
|
|
*/
|
|
public class AppLoader implements ApplicationListener {
|
|
|
|
/**
|
|
* 0xAA_BB_XXXX
|
|
* AA: Major version
|
|
* BB: Minor version
|
|
* XXXX: Revision (Repository commits, or something arbitrary)
|
|
* <p>
|
|
* e.g. 0x02010034 will be translated as 2.1.52
|
|
*/
|
|
public static final int VERSION_RAW = 0x00_02_0590;
|
|
|
|
public static final String getVERSION_STRING() {
|
|
return String.format("%d.%d.%d", VERSION_RAW >>> 24, (VERSION_RAW & 0xff0000) >>> 16, VERSION_RAW & 0xFFFF);
|
|
}
|
|
|
|
/**
|
|
* when FALSE, some assertion and print code will not execute
|
|
*/
|
|
public static boolean IS_DEVELOPMENT_BUILD = false;
|
|
|
|
|
|
/**
|
|
* Singleton instance
|
|
*/
|
|
private static AppLoader INSTANCE = null;
|
|
|
|
/**
|
|
* Screen injected at init, so that you run THAT screen instead of the main game.
|
|
*/
|
|
private static Screen injectScreen = null;
|
|
|
|
/**
|
|
* Initialise the application with the alternative Screen you choose
|
|
*
|
|
* @param appConfig LWJGL(2) Application Configuration
|
|
* @param injectScreen GDX Screen you want to run
|
|
*/
|
|
public AppLoader(LwjglApplicationConfiguration appConfig, Screen injectScreen) {
|
|
AppLoader.injectScreen = injectScreen;
|
|
AppLoader.appConfig = appConfig;
|
|
}
|
|
|
|
/**
|
|
* Initialise the application with default game screen
|
|
*
|
|
* @param appConfig LWJGL(2) Application Configuration
|
|
*/
|
|
public AppLoader(LwjglApplicationConfiguration appConfig) {
|
|
AppLoader.appConfig = appConfig;
|
|
}
|
|
|
|
/**
|
|
* Default null constructor. Don't use it.
|
|
*/
|
|
private AppLoader() {
|
|
}
|
|
|
|
/**
|
|
* Singleton pattern implementation in Java.
|
|
*
|
|
* @return
|
|
*/
|
|
public static AppLoader getINSTANCE() {
|
|
if (INSTANCE == null) {
|
|
INSTANCE = new AppLoader();
|
|
}
|
|
return INSTANCE;
|
|
}
|
|
|
|
public static final String GAME_NAME = "Terrarum";
|
|
public static final String COPYRIGHT_DATE_NAME = "Copyright 2013-2019 Torvald (minjaesong)";
|
|
public static String GAME_LOCALE = System.getProperty("user.language") + System.getProperty("user.country");
|
|
|
|
public static final String systemArch = System.getProperty("os.arch");
|
|
public static String processor;
|
|
public static String processorVendor;
|
|
public static String renderer;
|
|
public static String rendererVendor;
|
|
|
|
public static final boolean is32BitJVM = !System.getProperty("sun.arch.data.model").contains("64");
|
|
|
|
|
|
public static final float TV_SAFE_GRAPHICS = 0.05f; // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
|
|
public static final float TV_SAFE_ACTION = 0.035f; // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
|
|
|
|
public static int getTvSafeGraphicsWidth() { return Math.round(screenW * TV_SAFE_GRAPHICS); }
|
|
public static int getTvSafeGraphicsHeight() { return Math.round(screenH * TV_SAFE_GRAPHICS); }
|
|
public static int getTvSafeActionWidth() { return Math.round(screenW * TV_SAFE_ACTION); }
|
|
public static int getTvSafeActionHeight() { return Math.round(screenH * TV_SAFE_ACTION); }
|
|
|
|
/**
|
|
* These languages won't distinguish regional differences (e.g. enUS and enUK, frFR and frCA)
|
|
*/
|
|
private static final String[] localeSimple = {"de", "en", "es", "it"}; // must be sorted!!
|
|
|
|
public static String getSysLang() {
|
|
String lan = System.getProperty("user.language");
|
|
String country = System.getProperty("user.country");
|
|
return lan + country;
|
|
}
|
|
|
|
public static void setGAME_LOCALE(String value) {
|
|
if (value.isEmpty() || value.equals("")) {
|
|
GAME_LOCALE = getSysLang();
|
|
}
|
|
else {
|
|
try {
|
|
if (Arrays.binarySearch(localeSimple, value.substring(0, 2)) >= 0) {
|
|
GAME_LOCALE = value.substring(0, 2);
|
|
}
|
|
else {
|
|
GAME_LOCALE = value;
|
|
}
|
|
}
|
|
catch (StringIndexOutOfBoundsException e) {
|
|
GAME_LOCALE = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean splashDisplayed = false;
|
|
private static boolean postInitFired = false;
|
|
private static boolean screenshotRequested = false;
|
|
private static boolean resizeRequested = false;
|
|
private static Point2i resizeReqSize;
|
|
|
|
public static LwjglApplicationConfiguration appConfig;
|
|
public static GameFontBase fontGame;
|
|
public static TinyAlphNum fontSmallNumbers;
|
|
|
|
/** A gamepad. Multiple gamepads may controll this single virtualised gamepad. */
|
|
public static TerrarumController gamepad = null;
|
|
public static float gamepadDeadzone = 0.3f;
|
|
|
|
|
|
/**
|
|
* For the events depends on rendering frame (e.g. flicker on post-hit invincibility)
|
|
*/
|
|
public static int GLOBAL_RENDER_TIMER = new Random().nextInt(1020) + 1;
|
|
|
|
|
|
public static ArrayListMap debugTimers = new ArrayListMap<String, Long>();
|
|
|
|
public static final int defaultW = 1110;
|
|
public static final int defaultH = 740;
|
|
public static final int minimumW = 1080;
|
|
public static final int minimumH = 720;
|
|
|
|
public static void main(String[] args) {
|
|
// load configs
|
|
getDefaultDirectory();
|
|
createDirs();
|
|
readConfigJson();
|
|
|
|
|
|
try { processor = GetCpuName.getModelName(); }
|
|
catch (IOException e1) { processor = "Unknown CPU"; }
|
|
try { processorVendor = GetCpuName.getCPUID(); }
|
|
catch (IOException e2) { processorVendor = "Unknown CPU"; }
|
|
|
|
|
|
ShaderProgram.pedantic = false;
|
|
|
|
LwjglApplicationConfiguration appConfig = new LwjglApplicationConfiguration();
|
|
appConfig.useGL30 = true; // utilising some GL trickeries, need this to be TRUE
|
|
appConfig.vSyncEnabled = getConfigBoolean("usevsync");
|
|
appConfig.resizable = false;//true;
|
|
//appConfig.width = 1110; // photographic ratio (1.5:1)
|
|
//appConfig.height = 740; // photographic ratio (1.5:1)
|
|
appConfig.width = getConfigInt("screenwidth");
|
|
appConfig.height = getConfigInt("screenheight");
|
|
appConfig.backgroundFPS = getConfigInt("displayfps");
|
|
appConfig.foregroundFPS = getConfigInt("displayfps");
|
|
appConfig.title = GAME_NAME;
|
|
appConfig.forceExit = false;
|
|
|
|
// load app icon
|
|
int[] appIconSizes = new int[]{256,128,64,32,16};
|
|
for (int size : appIconSizes) {
|
|
String name = "assets/appicon" + size + ".png";
|
|
if (new File("./" + name).exists()) {
|
|
appConfig.addIcon(name, Files.FileType.Internal);
|
|
}
|
|
}
|
|
|
|
if (args.length == 1 && args[0].equals("isdev=true")) {
|
|
IS_DEVELOPMENT_BUILD = true;
|
|
// safe area box
|
|
//KeyToggler.INSTANCE.forceSet(Input.Keys.F11, true);
|
|
}
|
|
|
|
new LwjglApplication(new AppLoader(appConfig), appConfig);
|
|
}
|
|
|
|
|
|
private static ShaderProgram shaderBayerSkyboxFill;
|
|
public static ShaderProgram shaderHicolour;
|
|
public static ShaderProgram shaderPassthruRGB;
|
|
public static ShaderProgram shaderColLUT;
|
|
|
|
public static Mesh fullscreenQuad;
|
|
private OrthographicCamera camera;
|
|
private SpriteBatch logoBatch;
|
|
public static TextureRegion logo;
|
|
public static AudioDevice audioDevice;
|
|
|
|
private Color gradWhiteTop = new Color(0xf8f8f8ff);
|
|
private Color gradWhiteBottom = new Color(0xd8d8d8ff);
|
|
|
|
public Screen screen;
|
|
public static int screenW = 0;
|
|
public static int screenH = 0;
|
|
|
|
public static Texture textureWhiteSquare;
|
|
public static Texture textureWhiteCircle;
|
|
|
|
private void initViewPort(int width, int height) {
|
|
// Set Y to point downwards
|
|
camera.setToOrtho(true, width, height);
|
|
|
|
// Update camera matrix
|
|
camera.update();
|
|
|
|
// Set viewport to restrict drawing
|
|
Gdx.gl20.glViewport(0, 0, width, height);
|
|
}
|
|
|
|
public static final double UPDATE_RATE = 1.0 / 60.0; // TODO set it like 1/100, because apparent framerate is limited by update rate
|
|
|
|
private float loadTimer = 0f;
|
|
private final float showupTime = 100f / 1000f;
|
|
|
|
private FrameBuffer renderFBO;
|
|
|
|
public static CommonResourcePool resourcePool;
|
|
|
|
@Override
|
|
public void create() {
|
|
resourcePool = CommonResourcePool.INSTANCE;
|
|
|
|
|
|
// set basis of draw
|
|
logoBatch = new SpriteBatch();
|
|
camera = new OrthographicCamera(((float) appConfig.width), ((float) appConfig.height));
|
|
|
|
initViewPort(appConfig.width, appConfig.height);
|
|
|
|
// logo here :p
|
|
logo = new TextureRegion(new Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga")));
|
|
logo.flip(false, true);
|
|
|
|
// set GL graphics constants
|
|
shaderBayerSkyboxFill = loadShader("assets/4096.vert", "assets/4096_bayer_skyboxfill.frag");
|
|
shaderHicolour = loadShader("assets/4096.vert", "assets/hicolour.frag");
|
|
shaderPassthruRGB = loadShader("assets/4096.vert", "assets/passthrurgb.frag");
|
|
shaderColLUT = loadShader("assets/4096.vert", "assets/passthrurgb.frag");
|
|
|
|
fullscreenQuad = new Mesh(
|
|
true, 4, 6,
|
|
VertexAttribute.Position(),
|
|
VertexAttribute.ColorUnpacked(),
|
|
VertexAttribute.TexCoords(0)
|
|
);
|
|
updateFullscreenQuad(appConfig.width, appConfig.height);
|
|
|
|
|
|
// set up renderer info variables
|
|
renderer = Gdx.graphics.getGLVersion().getRendererString();
|
|
rendererVendor = Gdx.graphics.getGLVersion().getVendorString();
|
|
|
|
|
|
// make gamepad(s)
|
|
if (AppLoader.getConfigBoolean("usexinput")) {
|
|
try {
|
|
gamepad = new XinputControllerAdapter(XInputDevice.getDeviceFor(0));
|
|
}
|
|
catch (Throwable e) {
|
|
gamepad = null;
|
|
}
|
|
|
|
// nullify if not actually connected
|
|
try {
|
|
if (!((XinputControllerAdapter) gamepad).getC().isConnected()) {
|
|
gamepad = null;
|
|
}
|
|
}
|
|
catch (NullPointerException notQuiteWindows) {
|
|
gamepad = null;
|
|
}
|
|
}
|
|
|
|
if (gamepad == null) {
|
|
try {
|
|
gamepad = new GdxControllerAdapter(Controllers.getControllers().get(0));
|
|
}
|
|
catch (Throwable e) {
|
|
gamepad = null;
|
|
}
|
|
|
|
}
|
|
|
|
if (gamepad != null) {
|
|
environment = RunningEnvironment.CONSOLE;
|
|
|
|
// calibrate the sticks
|
|
printdbg(this, "Calibrating the gamepad...");
|
|
float[] axesZeroPoints = new float[]{
|
|
gamepad.getAxisRaw(0),
|
|
gamepad.getAxisRaw(1),
|
|
gamepad.getAxisRaw(2),
|
|
gamepad.getAxisRaw(3)
|
|
};
|
|
setConfig("gamepadaxiszeropoints", axesZeroPoints);
|
|
for (int i = 0; i < 4; i++) {
|
|
printdbg(this, "Axis " + i + ": " + axesZeroPoints[i]);
|
|
}
|
|
|
|
}
|
|
else {
|
|
environment = RunningEnvironment.PC;
|
|
}
|
|
|
|
// make loading list
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* @link http://bilgin.esme.org/BitsAndBytes/KalmanFilterforDummies
|
|
*/
|
|
private void updateKalmanRenderDelta() {
|
|
// moved to LwjglGraphics
|
|
}
|
|
|
|
@Override
|
|
public void render() {
|
|
Gdx.gl.glDisable(GL20.GL_DITHER);
|
|
|
|
if (splashDisplayed && !postInitFired) {
|
|
postInitFired = true;
|
|
postInit();
|
|
}
|
|
|
|
FrameBufferManager.begin(renderFBO);
|
|
gdxClearAndSetBlend(.094f, .094f, .094f, 0f);
|
|
setCameraPosition(0, 0);
|
|
|
|
// draw splash screen when predefined screen is null
|
|
// because in normal operation, the only time screen == null is when the app is cold-launched
|
|
// you can't have a text drawn here :v
|
|
if (screen == null) {
|
|
shaderBayerSkyboxFill.begin();
|
|
shaderBayerSkyboxFill.setUniformMatrix("u_projTrans", camera.combined);
|
|
shaderBayerSkyboxFill.setUniformf("parallax_size", 0f);
|
|
shaderBayerSkyboxFill.setUniformf("topColor", gradWhiteTop.r, gradWhiteTop.g, gradWhiteTop.b);
|
|
shaderBayerSkyboxFill.setUniformf("bottomColor", gradWhiteBottom.r, gradWhiteBottom.g, gradWhiteBottom.b);
|
|
fullscreenQuad.render(shaderBayerSkyboxFill, GL20.GL_TRIANGLES);
|
|
shaderBayerSkyboxFill.end();
|
|
|
|
logoBatch.begin();
|
|
logoBatch.setColor(Color.WHITE);
|
|
//blendNormal();
|
|
logoBatch.setShader(null);
|
|
|
|
|
|
setCameraPosition(0f, 0f);
|
|
logoBatch.draw(logo, (appConfig.width - logo.getRegionWidth()) / 2f,
|
|
(appConfig.height - logo.getRegionHeight()) / 2f
|
|
);
|
|
logoBatch.end();
|
|
|
|
|
|
loadTimer += Gdx.graphics.getRawDeltaTime();
|
|
|
|
if (loadTimer >= showupTime) {
|
|
// hand over the scene control to this single class; Terrarum must call
|
|
// 'AppLoader.getINSTANCE().screen.render(delta)', this is not redundant at all!
|
|
setScreen(Terrarum.INSTANCE);
|
|
}
|
|
}
|
|
// draw the screen
|
|
else {
|
|
screen.render((float) UPDATE_RATE);
|
|
}
|
|
|
|
KeyToggler.INSTANCE.update(screen instanceof Ingame);
|
|
|
|
// nested FBOs are just not a thing in GL!
|
|
net.torvald.terrarum.FrameBufferManager.end();
|
|
|
|
PostProcessor.INSTANCE.draw(camera.combined, renderFBO);
|
|
|
|
|
|
// process resize request
|
|
if (resizeRequested) {
|
|
resizeRequested = false;
|
|
resize(resizeReqSize.getX(), resizeReqSize.getY());
|
|
}
|
|
|
|
|
|
// process screenshot request
|
|
if (screenshotRequested) {
|
|
screenshotRequested = false;
|
|
|
|
try {
|
|
Pixmap p = ScreenUtils.getFrameBufferPixmap(0, 0, appConfig.width, appConfig.height);
|
|
PixmapIO2.writeTGA(Gdx.files.absolute(defaultDir + "/Screenshot.tga"), p, true);
|
|
p.dispose();
|
|
}
|
|
catch (Throwable e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
splashDisplayed = true;
|
|
GLOBAL_RENDER_TIMER += 1;
|
|
}
|
|
|
|
@Override
|
|
public void resize(int width, int height) {
|
|
printdbg(this, "Resize called");
|
|
for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
|
|
printdbg(this, stackTraceElement);
|
|
}
|
|
|
|
//initViewPort(width, height);
|
|
|
|
screenW = width;
|
|
screenH = height;
|
|
|
|
if (screenW % 2 == 1) screenW -= 1;
|
|
if (screenH % 2 == 1) screenH -= 1;
|
|
|
|
if (screen != null) screen.resize(screenW, screenH);
|
|
|
|
|
|
if (renderFBO == null ||
|
|
(renderFBO.getWidth() != screenW ||
|
|
renderFBO.getHeight() != screenH)
|
|
) {
|
|
renderFBO = new FrameBuffer(
|
|
Pixmap.Format.RGBA8888,
|
|
screenW,
|
|
screenH,
|
|
false
|
|
);
|
|
}
|
|
|
|
appConfig.width = screenW;
|
|
appConfig.height = screenH;
|
|
|
|
updateFullscreenQuad(screenW, screenH);
|
|
|
|
printdbg(this, "Resize end");
|
|
}
|
|
|
|
public static void resizeScreen(int width, int height) {
|
|
resizeRequested = true;
|
|
resizeReqSize = new Point2i(Math.max(width, minimumW), Math.max(height, minimumH));
|
|
}
|
|
|
|
@Override
|
|
public void dispose() {
|
|
System.out.println("Goodbye !");
|
|
|
|
|
|
if (screen != null) {
|
|
screen.hide();
|
|
screen.dispose();
|
|
}
|
|
|
|
IngameRenderer.INSTANCE.dispose();
|
|
PostProcessor.INSTANCE.dispose();
|
|
MinimapComposer.INSTANCE.dispose();
|
|
|
|
Terrarum.INSTANCE.dispose();
|
|
|
|
shaderBayerSkyboxFill.dispose();
|
|
shaderHicolour.dispose();
|
|
shaderPassthruRGB.dispose();
|
|
shaderColLUT.dispose();
|
|
|
|
resourcePool.dispose();
|
|
fullscreenQuad.dispose();
|
|
logoBatch.dispose();
|
|
|
|
fontGame.dispose();
|
|
fontSmallNumbers.dispose();
|
|
|
|
textureWhiteSquare.dispose();
|
|
textureWhiteCircle.dispose();
|
|
logo.getTexture().dispose();
|
|
|
|
ModMgr.INSTANCE.disposeMods();
|
|
|
|
// delete temp files
|
|
new File("./tmp_wenquanyi.tga").delete(); // FIXME this is pretty much ad-hoc
|
|
}
|
|
|
|
@Override
|
|
public void pause() {
|
|
if (screen != null) screen.pause();
|
|
}
|
|
|
|
@Override
|
|
public void resume() {
|
|
if (screen != null) screen.resume();
|
|
}
|
|
|
|
public void setScreen(Screen screen) {
|
|
printdbg(this, "Changing screen to " + screen.getClass().getCanonicalName());
|
|
|
|
// this whole thing is directtly copied from com.badlogic.gdx.Game
|
|
|
|
if (this.screen != null) {
|
|
this.screen.hide();
|
|
this.screen.dispose();
|
|
}
|
|
this.screen = screen;
|
|
if (this.screen != null) {
|
|
this.screen.show();
|
|
this.screen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
|
}
|
|
|
|
System.gc();
|
|
|
|
printdbg(this, "Screen transisiton complete: " + this.screen.getClass().getCanonicalName());
|
|
}
|
|
|
|
/**
|
|
* Init stuffs which needs GL context
|
|
*/
|
|
private void postInit() {
|
|
textureWhiteSquare = new Texture(Gdx.files.internal("assets/graphics/ortho_line_tex_2px.tga"));
|
|
textureWhiteSquare.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
|
|
|
|
textureWhiteCircle = new Texture(Gdx.files.internal("assets/graphics/circle_512.tga"));
|
|
textureWhiteCircle.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
|
|
|
|
TextureRegionPack.Companion.setGlobalFlipY(true);
|
|
fontGame = new GameFontBase("assets/graphics/fonts/terrarum-sans-bitmap", false, true,
|
|
Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest, false, 256, false
|
|
);
|
|
fontSmallNumbers = TinyAlphNum.INSTANCE;
|
|
|
|
try {
|
|
audioDevice = Gdx.audio.newAudioDevice(48000, false);
|
|
}
|
|
catch (NullPointerException deviceInUse) {
|
|
deviceInUse.printStackTrace();
|
|
System.err.println("[AppLoader] failed to create audio device: Audio device occupied by Exclusive Mode Device? (e.g. ASIO4all)");
|
|
}
|
|
|
|
// if there is a predefined screen, open that screen after my init process
|
|
if (injectScreen != null) {
|
|
setScreen(injectScreen);
|
|
}
|
|
|
|
|
|
ModMgr.INSTANCE.invoke(); // invoke Module Manager
|
|
AppLoader.resourcePool.loadAll();
|
|
printdbg(this, "all modules loaded successfully");
|
|
|
|
|
|
BlocksDrawer.INSTANCE.getWorld(); // will initialize the BlocksDrawer by calling dummy method
|
|
LightmapRenderer.INSTANCE.hdr(0f);
|
|
|
|
|
|
printdbg(this, "PostInit done");
|
|
}
|
|
|
|
|
|
private void setCameraPosition(float newX, float newY) {
|
|
camera.position.set((-newX + appConfig.width / 2), (-newY + appConfig.height / 2), 0f);
|
|
camera.update();
|
|
logoBatch.setProjectionMatrix(camera.combined);
|
|
}
|
|
|
|
private void updateFullscreenQuad(int WIDTH, int HEIGHT) { // NOT y-flipped quads!
|
|
fullscreenQuad.setVertices(new float[]{
|
|
0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f,
|
|
WIDTH, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f,
|
|
WIDTH, HEIGHT, 0f, 1f, 1f, 1f, 1f, 1f, 0f,
|
|
0f, HEIGHT, 0f, 1f, 1f, 1f, 1f, 0f, 0f
|
|
});
|
|
fullscreenQuad.setIndices(new short[]{0, 1, 2, 2, 3, 0});
|
|
}
|
|
|
|
public static void requestScreenshot() {
|
|
screenshotRequested = true;
|
|
}
|
|
|
|
// DEFAULT DIRECTORIES //
|
|
|
|
public static String OSName = System.getProperty("os.name");
|
|
public static String OSVersion = System.getProperty("os.version");
|
|
public static String operationSystem;
|
|
/** %appdata%/Terrarum, without trailing slash */
|
|
public static String defaultDir;
|
|
/** defaultDir + "/Saves", without trailing slash */
|
|
public static String defaultSaveDir;
|
|
/** defaultDir + "/config.json" */
|
|
public static String configDir;
|
|
public static RunningEnvironment environment;
|
|
|
|
private static void getDefaultDirectory() {
|
|
String OS = OSName.toUpperCase();
|
|
if (OS.contains("WIN")) {
|
|
operationSystem = "WINDOWS";
|
|
defaultDir = System.getenv("APPDATA") + "/Terrarum";
|
|
}
|
|
else if (OS.contains("OS X")) {
|
|
operationSystem = "OSX";
|
|
defaultDir = System.getProperty("user.home") + "/Library/Application Support/Terrarum";
|
|
}
|
|
else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) {
|
|
operationSystem = "LINUX";
|
|
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
|
}
|
|
else if (OS.contains("SUNOS")) {
|
|
operationSystem = "SOLARIS";
|
|
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
|
}
|
|
/*else if (System.getProperty("java.runtime.name").toUpperCase().contains("ANDROID")) {
|
|
operationSystem = "ANDROID";
|
|
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
|
environment = RunningEnvironment.MOBILE;
|
|
}*/
|
|
else {
|
|
operationSystem = "UNKNOWN";
|
|
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
|
}
|
|
|
|
defaultSaveDir = defaultDir + "/Saves";
|
|
configDir = defaultDir + "/config.json";
|
|
|
|
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
|
|
System.out.println(String.format("os.version = %s", OSVersion));
|
|
System.out.println(String.format("default directory: %s", defaultDir));
|
|
System.out.println(String.format("java version = %s", System.getProperty("java.version")));
|
|
}
|
|
|
|
private static void createDirs() {
|
|
File[] dirs = {new File(defaultSaveDir)};
|
|
|
|
for (File it : dirs) {
|
|
if (!it.exists())
|
|
it.mkdirs();
|
|
}
|
|
|
|
//dirs.forEach { if (!it.exists()) it.mkdirs() }
|
|
}
|
|
|
|
|
|
// CONFIG //
|
|
|
|
private static KVHashMap gameConfig = new KVHashMap();
|
|
|
|
private static void createConfigJson() throws IOException {
|
|
File configFile = new File(configDir);
|
|
|
|
if (!configFile.exists() || configFile.length() == 0L) {
|
|
JsonWriter.INSTANCE.writeToFile(DefaultConfig.INSTANCE.fetch(), configDir);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return true on successful, false on failure.
|
|
*/
|
|
private static Boolean readConfigJson() {
|
|
try {
|
|
// read from disk and build config from it
|
|
JsonObject jsonObject = JsonFetcher.INSTANCE.invoke(configDir);
|
|
|
|
// make config
|
|
jsonObject.entrySet().forEach((entry) ->
|
|
gameConfig.set(entry.getKey(), entry.getValue())
|
|
);
|
|
|
|
return true;
|
|
}
|
|
catch (java.nio.file.NoSuchFileException e) {
|
|
// write default config to game dir. Call this method again to read config from it.
|
|
try {
|
|
createConfigJson();
|
|
}
|
|
catch (IOException e1) {
|
|
System.out.println("[AppLoader] Unable to write config.json file");
|
|
e.printStackTrace();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Return config from config set. If the config does not exist, default value will be returned.
|
|
* @param key
|
|
* *
|
|
* @return Config from config set or default config if it does not exist.
|
|
* *
|
|
* @throws NullPointerException if the specified config simply does not exist.
|
|
*/
|
|
public static int getConfigInt(String key) {
|
|
Object cfg = getConfigMaster(key);
|
|
if (cfg instanceof JsonPrimitive)
|
|
return ((JsonPrimitive) cfg).getAsInt();
|
|
else
|
|
return Integer.parseInt(((String) cfg));
|
|
}
|
|
|
|
/**
|
|
* Return config from config set. If the config does not exist, default value will be returned.
|
|
* @param key
|
|
* *
|
|
* @return Config from config set or default config if it does not exist.
|
|
* *
|
|
* @throws NullPointerException if the specified config simply does not exist.
|
|
*/
|
|
public static String getConfigString(String key) {
|
|
Object cfg = getConfigMaster(key);
|
|
if (cfg instanceof JsonPrimitive)
|
|
return ((JsonPrimitive) cfg).getAsString();
|
|
else
|
|
return ((String) cfg);
|
|
}
|
|
|
|
/**
|
|
* Return config from config set. If the config does not exist, default value will be returned.
|
|
* @param key
|
|
* *
|
|
* @return Config from config set or default config if it does not exist. If the default value is undefined, will return false.
|
|
*/
|
|
public static boolean getConfigBoolean(String key) {
|
|
try {
|
|
Object cfg = getConfigMaster(key);
|
|
if (cfg instanceof JsonPrimitive)
|
|
return ((JsonPrimitive) cfg).getAsBoolean();
|
|
else
|
|
return ((boolean) cfg);
|
|
}
|
|
catch (NullPointerException keyNotFound) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static int[] getConfigIntArray(String key) {
|
|
Object cfg = getConfigMaster(key);
|
|
if (cfg instanceof JsonArray) {
|
|
JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray();
|
|
//return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
|
|
int[] intArray = new int[jsonArray.size()];
|
|
for (int i = 0; i < jsonArray.size(); i++) {
|
|
intArray[i] = jsonArray.get(i).getAsInt();
|
|
}
|
|
return intArray;
|
|
}
|
|
else
|
|
return ((int[]) cfg);
|
|
}
|
|
|
|
public static float[] getConfigFloatArray(String key) {
|
|
Object cfg = getConfigMaster(key);
|
|
if (cfg instanceof JsonArray) {
|
|
JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray();
|
|
//return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
|
|
float[] floatArray = new float[jsonArray.size()];
|
|
for (int i = 0; i < jsonArray.size(); i++) {
|
|
floatArray[i] = jsonArray.get(i).getAsInt();
|
|
}
|
|
return floatArray;
|
|
}
|
|
else
|
|
return ((float[]) cfg);
|
|
}
|
|
|
|
/**
|
|
* Get config from config file. If the entry does not exist, get from defaults; if the entry is not in the default, NullPointerException will be thrown
|
|
*/
|
|
private static JsonObject getDefaultConfig() {
|
|
return DefaultConfig.INSTANCE.fetch();
|
|
}
|
|
|
|
private static Object getConfigMaster(String key1) {
|
|
String key = key1.toLowerCase();
|
|
|
|
Object config;
|
|
try {
|
|
config = gameConfig.get(key);
|
|
}
|
|
catch (NullPointerException e) {
|
|
config = null;
|
|
}
|
|
|
|
Object defaults;
|
|
try {
|
|
defaults = getDefaultConfig().get(key);
|
|
}
|
|
catch (NullPointerException e) {
|
|
defaults = null;
|
|
}
|
|
|
|
if (config == null) {
|
|
if (defaults == null) {
|
|
throw new NullPointerException("key not found: '" + key + "'");
|
|
}
|
|
else {
|
|
return defaults;
|
|
}
|
|
}
|
|
else {
|
|
return config;
|
|
}
|
|
}
|
|
|
|
public static void setConfig(String key, Object value) {
|
|
gameConfig.set(key.toLowerCase(), value);
|
|
}
|
|
|
|
|
|
|
|
// //
|
|
|
|
public static void printdbg(Object obj, Object message) {
|
|
if (IS_DEVELOPMENT_BUILD) {
|
|
System.out.println("[" + obj.getClass().getSimpleName() + "] " + message.toString());
|
|
}
|
|
}
|
|
|
|
public static void printdbgerr(Object obj, Object message) {
|
|
if (IS_DEVELOPMENT_BUILD) {
|
|
System.err.println("[" + obj.getClass().getSimpleName() + "] " + message.toString());
|
|
}
|
|
}
|
|
|
|
public static void printmsg(Object obj, Object message) {
|
|
System.out.println("[" + obj.getClass().getSimpleName() + "] " + message.toString());
|
|
}
|
|
|
|
public static ShaderProgram loadShader(String vert, String frag) {
|
|
ShaderProgram s = new ShaderProgram(Gdx.files.internal(vert), Gdx.files.internal(frag));
|
|
|
|
if (s.getLog().toLowerCase().contains("error")) {
|
|
throw new Error(String.format("Shader program loaded with %s, %s failed:\n%s", vert, frag, s.getLog()));
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
public static void measureDebugTime(String name, kotlin.jvm.functions.Function0<kotlin.Unit> block) {
|
|
if (IS_DEVELOPMENT_BUILD) {
|
|
//debugTimers.put(name, kotlin.system.TimingKt.measureNanoTime(block));
|
|
|
|
long start = System.nanoTime();
|
|
block.invoke();
|
|
debugTimers.put(name, System.nanoTime() - start);
|
|
}
|
|
}
|
|
|
|
public static void setDebugTime(String name, long value) {
|
|
if (IS_DEVELOPMENT_BUILD) {
|
|
debugTimers.put(name, value);
|
|
}
|
|
}
|
|
|
|
public static void addDebugTime(String target, String... targets) {
|
|
if (IS_DEVELOPMENT_BUILD) {
|
|
long l = 0L;
|
|
for (String s : targets) {
|
|
l += ((long) debugTimers.get(s));
|
|
}
|
|
debugTimers.put(target, l);
|
|
}
|
|
}
|
|
} |