diff --git a/CHANGES.md b/CHANGES.md index 0033370d..c1c43993 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ [1.0.0-SNAPSHOT] +[1.0.0-b4] +- Fix an issue with TeaClassloader that was giving annotation error when building artemis games +- Bugfix: Asset Loading should not re-Download 403 Errors +- Bugfix for density calculation. +- Bugfix: blank line on top of HTML body on mobile. +- Bugfix: Asset Loading & Error "ERR_HTTP2_SERVER_REFUSED_STREAM + [1.0.0-b3] - Add gdx-bullet c++ module so desktop and web use the same c++ code/version - Update teaVM to 0.8.0-dev-1 and project Java version to 11 diff --git a/backends/backend-teavm/emu/com/artemis/utils/reflect/AnnotationEmu.java b/backends/backend-teavm/emu/com/artemis/utils/reflect/Annotation.java similarity index 75% rename from backends/backend-teavm/emu/com/artemis/utils/reflect/AnnotationEmu.java rename to backends/backend-teavm/emu/com/artemis/utils/reflect/Annotation.java index 841f11c0..171cd792 100644 --- a/backends/backend-teavm/emu/com/artemis/utils/reflect/AnnotationEmu.java +++ b/backends/backend-teavm/emu/com/artemis/utils/reflect/Annotation.java @@ -1,18 +1,15 @@ package com.artemis.utils.reflect; -import com.github.xpenatan.gdx.backends.teavm.gen.Emulate; - /** * Provides information about, and access to, an annotation of a field, class or interface. * * @author dludwig */ -@Emulate(valueStr = "com.artemis.utils.reflect.Annotation") -public final class AnnotationEmu { +public final class Annotation { private java.lang.annotation.Annotation annotation; - AnnotationEmu(java.lang.annotation.Annotation annotation) { + Annotation(java.lang.annotation.Annotation annotation) { this.annotation = annotation; } diff --git a/backends/backend-teavm/emu/com/artemis/utils/reflect/Field.java b/backends/backend-teavm/emu/com/artemis/utils/reflect/Field.java new file mode 100644 index 00000000..51d708d9 --- /dev/null +++ b/backends/backend-teavm/emu/com/artemis/utils/reflect/Field.java @@ -0,0 +1,7 @@ +package com.artemis.utils.reflect; + +public final class Field extends FieldGen { + public Field(java.lang.reflect.Field field) { + super(field); + } +} \ No newline at end of file diff --git a/backends/backend-teavm/emu/com/artemis/utils/reflect/FieldEmu.java b/backends/backend-teavm/emu/com/artemis/utils/reflect/FieldEmu.java deleted file mode 100644 index d7158042..00000000 --- a/backends/backend-teavm/emu/com/artemis/utils/reflect/FieldEmu.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.artemis.utils.reflect; - -import com.github.xpenatan.gdx.backends.teavm.gen.Emulate; - -@Emulate(valueStr = "com.artemis.utils.reflect.Field") -public final class FieldEmu extends FieldGen { - public FieldEmu(java.lang.reflect.Field field) { - super(field); - } -} - diff --git a/backends/backend-teavm/emu/com/artemis/utils/reflect/FieldGen.java b/backends/backend-teavm/emu/com/artemis/utils/reflect/FieldGen.java index f6b9a9eb..f4568fce 100644 --- a/backends/backend-teavm/emu/com/artemis/utils/reflect/FieldGen.java +++ b/backends/backend-teavm/emu/com/artemis/utils/reflect/FieldGen.java @@ -157,28 +157,30 @@ private static void getElementType(ReflectClass cls, Value fieldNameV Value result = Metaprogramming.lazy(() -> null); for(ReflectField field : cls.getDeclaredFields()) { java.lang.reflect.Field javaField = genericTypeProvider.findField(field); - Type genericType = javaField.getGenericType(); - if(genericType instanceof ParameterizedType) { - Type[] actualTypes = ((ParameterizedType)genericType).getActualTypeArguments(); - - if(actualTypes != null) { - for(int i = 0; i < actualTypes.length; i++) { - Class actualType = getActualType(actualTypes[i]); - if(actualType == null) - continue; - found = true; - final int index = i; - - String fieldName = field.getName(); - Value existing = result; - result = Metaprogramming.lazy(() -> { - if(index == indexValue.get()) { - if(fieldName.equals(fieldNameValue.get())) { - return actualType; + if (javaField != null) { + Type genericType = javaField.getGenericType(); + if (genericType instanceof ParameterizedType) { + Type[] actualTypes = ((ParameterizedType) genericType).getActualTypeArguments(); + + if (actualTypes != null) { + for (int i = 0; i < actualTypes.length; i++) { + Class actualType = getActualType(actualTypes[i]); + if (actualType == null) + continue; + found = true; + final int index = i; + + String fieldName = field.getName(); + Value existing = result; + result = Metaprogramming.lazy(() -> { + if (index == indexValue.get()) { + if (fieldName.equals(fieldNameValue.get())) { + return actualType; + } } - } - return existing.get(); - }); + return existing.get(); + }); + } } } } @@ -201,7 +203,7 @@ public Class getElementType(int index) { } public T getAnnotation(Class annotationClass) { - final AnnotationEmu declaredAnnotation = getDeclaredAnnotation(annotationClass); + final Annotation declaredAnnotation = getDeclaredAnnotation(annotationClass); return declaredAnnotation != null ? declaredAnnotation.getAnnotation(annotationClass) : null; } @@ -212,23 +214,23 @@ public boolean isAnnotationPresent(Class annotationType) { + public Annotation getDeclaredAnnotation(Class annotationType) { java.lang.annotation.Annotation[] annotations = field.getDeclaredAnnotations(); if(annotations == null) { return null; } for(java.lang.annotation.Annotation annotation : annotations) { if(annotation.annotationType().equals(annotationType)) { - return new AnnotationEmu(annotation); + return new Annotation(annotation); } } return null; diff --git a/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/AnnotationEmu.java b/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/Annotation.java similarity index 78% rename from backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/AnnotationEmu.java rename to backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/Annotation.java index 2015c152..c1712ebc 100644 --- a/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/AnnotationEmu.java +++ b/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/Annotation.java @@ -1,18 +1,15 @@ package com.badlogic.gdx.utils.reflect; -import com.github.xpenatan.gdx.backends.teavm.gen.Emulate; - /** * Provides information about, and access to, an annotation of a field, class or interface. * * @author dludwig */ -@Emulate(Annotation.class) -public final class AnnotationEmu { +public final class Annotation { private java.lang.annotation.Annotation annotation; - AnnotationEmu(java.lang.annotation.Annotation annotation) { + Annotation(java.lang.annotation.Annotation annotation) { this.annotation = annotation; } diff --git a/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/Field.java b/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/Field.java new file mode 100644 index 00000000..e956fa61 --- /dev/null +++ b/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/Field.java @@ -0,0 +1,7 @@ +package com.badlogic.gdx.utils.reflect; + +public final class Field extends FieldGen{ + public Field(java.lang.reflect.Field field) { + super(field); + } +} \ No newline at end of file diff --git a/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/FieldEmu.java b/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/FieldEmu.java deleted file mode 100644 index cac224fa..00000000 --- a/backends/backend-teavm/emu/com/badlogic/gdx/utils/reflect/FieldEmu.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.badlogic.gdx.utils.reflect; - -import com.github.xpenatan.gdx.backends.teavm.gen.Emulate; - -@Emulate(Field.class) -public final class FieldEmu extends FieldGen{ - public FieldEmu(java.lang.reflect.Field field) { - super(field); - } -} diff --git a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaBuilder.java b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaBuilder.java index 0c3c8992..0946d408 100644 --- a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaBuilder.java +++ b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaBuilder.java @@ -2,7 +2,6 @@ import com.badlogic.gdx.files.FileHandle; import com.github.xpenatan.gdx.backends.teavm.gen.SkipClass; -import com.github.xpenatan.gdx.backends.teavm.plugins.TeaClassFilter; import com.github.xpenatan.gdx.backends.teavm.plugins.TeaClassTransformer; import com.github.xpenatan.gdx.backends.teavm.plugins.TeaReflectionSupplier; import com.github.xpenatan.gdx.backends.teavm.preloader.AssetFilter; @@ -20,7 +19,6 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.reflections.Reflections; import org.teavm.diagnostics.DefaultProblemTextConsumer; import org.teavm.diagnostics.Problem; import org.teavm.diagnostics.ProblemProvider; @@ -204,7 +202,8 @@ private static void preserveClasses(TeaVMTool tool, TeaBuildConfiguration config ArrayList configClassesToPreserve = configuration.getClassesToPreserve(); List reflectionClasses = TeaReflectionSupplier.getReflectionClasses(); configClassesToPreserve.addAll(reflectionClasses); - ArrayList preserveClasses = classLoader.getPreserveClasses(configClassesToPreserve); + // Get classes or packages from reflection. When path is a package, get all classes from it. + ArrayList preserveClasses = classLoader.getAllClasses(configClassesToPreserve); classesToPreserve.addAll(preserveClasses); } @@ -551,12 +550,6 @@ public TeaVMProgressFeedback progressReached(int i) { } }); preserveClasses(tool, configuration, classLoader); - - //TODO Remove -// Properties properties = tool.getProperties(); -// properties.put("teavm.libgdx.fsJsonPath", webappDirectory + File.separator + webappName + File.separator + "filesystem.json"); -// properties.put("teavm.libgdx.warAssetsDirectory", webappDirectory + File.separator + webappName + File.separator + "assets"); - } public static void configAssets(TeaClassLoader classLoader, TeaBuildConfiguration configuration, String webappDirectory, String webappName) { diff --git a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaClassLoader.java b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaClassLoader.java index 4c2f7af8..28e8ca53 100644 --- a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaClassLoader.java +++ b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaClassLoader.java @@ -2,7 +2,6 @@ import java.io.File; import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -28,68 +27,6 @@ public TeaClassLoader(URL[] classPaths, ClassLoader parent, ArrayList sk this.skipClasses.addAll(skipClasses); } - @Override - public URL getResource(String name) { - return getRes(name); - } - - private URL getRes(String name) { - String fixName = name.replace(";.class", ".class"); - fixName = fixName.replace("[L", ""); - fixName = fixName.replace("[", ""); - - String toPackage = fixName.replace("/", "."); - if(containsSkipClass(toPackage)) { - return null; - } - - URL resource = super.getResource(name); - for(int i = 0; i < jarFiles.length; i++) { - URL url = jarFiles[i]; - String path = url.getPath(); - String finalFile = "jar:file:" + path + "!/"; - File file = new File(path); - if(file.exists()) { - if(!file.isDirectory()) { - try { - JarFile jarFile = new JarFile(file); - Enumeration entries = jarFile.entries(); - while(entries.hasMoreElements()) { - JarEntry jarEntry = entries.nextElement(); - if(!jarEntry.isDirectory()) { - String jarEntryName = jarEntry.getName(); - if(jarEntryName.equals(fixName)) { - String filee = finalFile + jarEntryName; - return new URL(filee); - } - } - } - } - catch(Exception e) { - e.printStackTrace(); - } - } - else { - try { - ArrayList allClasses = getAllFiles(path); - String resName = fixName.replace("\\", "/"); - for(int j = 0; j < allClasses.size(); j++) { - String className = allClasses.get(j); - if(className.contains(resName)) { - String filee = path + className; - return new File(filee).toURI().toURL(); - } - } - } - catch(MalformedURLException e) { - e.printStackTrace(); - } - } - } - } - return resource; - } - @Override public InputStream getResourceAsStream(String name) { String fixName = name.replace(";.class", ".class"); @@ -119,6 +56,7 @@ public InputStream getResourceAsStream(String name) { } } else { + // This probably not working and need to remove. ArrayList allClasses = getAllFiles(path); String resName = fixName.replace("\\", "/"); for(int j = 0; j < allClasses.size(); j++) { @@ -131,11 +69,7 @@ public InputStream getResourceAsStream(String name) { } } - if(fixName.startsWith("org/teavm/")) { - return super.getResourceAsStream(name); - } - - return null; + return super.getResourceAsStream(name); } private boolean containsSkipClass(String clazz) { @@ -181,13 +115,13 @@ private void getAllFiles(File rootFile, ArrayList out, String packageNam /** * Convert packages to individual classes */ - public ArrayList getPreserveClasses(ArrayList classesToPreserve) { + public ArrayList getAllClasses(ArrayList classOrPackage) { // TeaVM only accept individual classes. We need to obtain all classes from package (if its set). // If it's not a package just add the class. ArrayList array = new ArrayList<>(); - for(int i = 0; i < classesToPreserve.size(); i++) { - String className = classesToPreserve.get(i); + for(int i = 0; i < classOrPackage.size(); i++) { + String className = classOrPackage.get(i); String packagePath = className.replace(".", "/"); URL resource = getResource(packagePath + ".class"); if(resource == null) { diff --git a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaGraphics.java b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaGraphics.java index 84eb73c2..0160ef65 100644 --- a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaGraphics.java +++ b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaGraphics.java @@ -186,13 +186,13 @@ public GLVersion getGLVersion() { } @Override - public float getPpiX() { - return 96; + public float getPpiX () { + return 96f * (float)getNativeScreenDensity(); } @Override - public float getPpiY() { - return 96; + public float getPpiY () { + return 96f * (float)getNativeScreenDensity(); } @Override @@ -206,8 +206,9 @@ public float getPpcY() { } @Override - public float getDensity() { - return 96.0f / 160; + public float getDensity () { + float ppiX = getPpiX(); + return (ppiX > 0 && ppiX <= Float.MAX_VALUE) ? ppiX / 160f : 1f; } @Override diff --git a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaInput.java b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaInput.java index a13b9458..d7689d9d 100644 --- a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaInput.java +++ b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/TeaInput.java @@ -141,8 +141,8 @@ private void handleMouseEvents(EventWrapper e) { this.deltaX[0] = 0; this.deltaY[0] = 0; if(isCursorCatched()) { - this.touchX[0] += getMovementXJS(mouseEvent); - this.touchY[0] += getMovementYJS(mouseEvent); + this.touchX[0] += mouseEvent.getMovementX(); + this.touchY[0] += mouseEvent.getMovementY(); } else { int relativeX = getRelativeX(mouseEvent, canvas); @@ -163,9 +163,9 @@ else if(type.equals("mouseup")) { this.pressedButtons.remove(KeyCodes.getButton(mouseEvent.getButton())); this.touched[0] = pressedButtons.size > 0; if(isCursorCatched()) { - setDelta(0, (int)getMovementXJS(mouseEvent), (int)getMovementYJS(mouseEvent)); - this.touchX[0] += getMovementXJS(mouseEvent); - this.touchY[0] += getMovementYJS(mouseEvent); + setDelta(0, (int)mouseEvent.getMovementX(), (int)mouseEvent.getMovementY()); + this.touchX[0] += mouseEvent.getMovementX(); + this.touchY[0] += mouseEvent.getMovementY(); } else { setDelta(0, getRelativeX(mouseEvent, canvas) - touchX[0], getRelativeY(mouseEvent, canvas) - touchY[0]); @@ -180,9 +180,9 @@ else if(type.equals("mouseup")) { else if(type.equals("mousemove")) { MouseEventWrapper mouseEvent = (MouseEventWrapper)e; if(isCursorCatched()) { - setDelta(0, (int)getMovementXJS(mouseEvent), (int)getMovementYJS(mouseEvent)); - this.touchX[0] += getMovementXJS(mouseEvent); - this.touchY[0] += getMovementYJS(mouseEvent); + setDelta(0, (int)mouseEvent.getMovementX(), (int)mouseEvent.getMovementY()); + this.touchX[0] += mouseEvent.getMovementX(); + this.touchY[0] += mouseEvent.getMovementY(); } else { int relativeX = getRelativeX(mouseEvent, canvas); @@ -390,30 +390,6 @@ public void setDelta(int touchId, int x, int y) { deltaY[touchId] = y; } - /** - * from https://github.com/toji/game-shim/blob/master/game-shim.js - * - * @param event JavaScript Mouse Event - * @return movement in x direction - */ - private float getMovementXJS(MouseEventWrapper event) { - return event.getMovementX(); - } - - ; - - /** - * from https://github.com/toji/game-shim/blob/master/game-shim.js - * - * @param event JavaScript Mouse Event - * @return movement in y direction - */ - private float getMovementYJS(MouseEventWrapper event) { - return event.getMovementY(); - } - - ; - private ElementWrapper getCompatMode(HTMLDocumentWrapper target) { String compatMode = target.getCompatMode(); boolean isComp = compatMode.equals("CSS1Compat"); @@ -813,8 +789,7 @@ public boolean isCursorCatched() { @Override public void setCursorPosition(int x, int y) { - // TODO Auto-generated method stub - + // not possible in a browser window } @Override diff --git a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/preloader/AssetDownloadImpl.java b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/preloader/AssetDownloadImpl.java index 537aa4c0..b710ce5e 100644 --- a/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/preloader/AssetDownloadImpl.java +++ b/backends/backend-teavm/src/main/java/com/github/xpenatan/gdx/backends/teavm/preloader/AssetDownloadImpl.java @@ -23,8 +23,8 @@ public class AssetDownloadImpl implements AssetDownload { private int queue; - private boolean useBrowserCache = true; - private boolean useInlineBase64; + private boolean useBrowserCache = false; + private boolean useInlineBase64 = false; private boolean showLog = true; @@ -33,7 +33,7 @@ public AssetDownloadImpl() { @Override public boolean isUseBrowserCache() { - return false; + return useBrowserCache; } @Override @@ -86,63 +86,100 @@ public void load(boolean async, String url, AssetType type, String mimeType, Ass public void loadText(boolean async, String url, AssetLoaderListener listener) { if(showLog) System.out.println("Loading asset : " + url); - final XMLHttpRequestWrapper request = (XMLHttpRequestWrapper)XMLHttpRequest.create(); - request.setOnreadystatechange(new EventHandlerWrapper() { - @Override - public void handleEvent(EventWrapper evt) { - if(request.getReadyState() == XMLHttpRequestWrapper.DONE) { - if(request.getStatus() != 200) { - listener.onFailure(url); - } - else { - if(showLog) - System.out.println("Asset loaded: " + url); - listener.onSuccess(url, request.getResponseText()); + + // don't load on main thread + addQueue(); + new Thread() { + public void run() { + final XMLHttpRequestWrapper request = (XMLHttpRequestWrapper)XMLHttpRequest.create(); + request.setOnreadystatechange(new EventHandlerWrapper() { + @Override + public void handleEvent(EventWrapper evt) { + if(request.getReadyState() == XMLHttpRequestWrapper.DONE) { + if(request.getStatus() != 200) { + if ((request.getStatus() != 404) && + (request.getStatus() != 403)) { + // re-try: e.g. failure due to ERR_HTTP2_SERVER_REFUSED_STREAM (too many requests) + try { + Thread.sleep(100); + } + catch (Throwable e) { + // ignored + } + loadText(async, url, listener); + } + else { + listener.onFailure(url); + } + } + else { + if(showLog) + System.out.println("Asset loaded: " + url); + listener.onSuccess(url, request.getResponseText()); + } + subtractQueue(); + } } - subtractQueue(); - } + }); + setOnProgress(request, listener); + request.open("GET", url, async); + request.setRequestHeader("Content-Type", "text/plain; charset=utf-8"); + request.send(); } - }); - addQueue(); - setOnProgress(request, listener); - request.open("GET", url, async); - request.setRequestHeader("Content-Type", "text/plain; charset=utf-8"); - request.send(); + }.start(); } @Override public void loadScript(boolean async, String url, AssetLoaderListener listener) { if(showLog) System.out.println("Loading script : " + url); - final XMLHttpRequestWrapper request = (XMLHttpRequestWrapper)XMLHttpRequest.create(); - request.setOnreadystatechange(new EventHandlerWrapper() { - @Override - public void handleEvent(EventWrapper evt) { - if(request.getReadyState() == XMLHttpRequestWrapper.DONE) { - boolean subtractQueue = true; - if(request.getStatus() != 200) { - listener.onFailure(url); - } - else { - if(showLog) - System.out.println("Script loaded: " + url); - NodeWrapper response = request.getResponse(); - TeaWindow currentWindow = TeaWindow.get(); - DocumentWrapper document = currentWindow.getDocument(); - HTMLElementWrapper scriptElement = document.createElement("script"); - scriptElement.appendChild(document.createTextNode(response)); - document.getBody().appendChild(scriptElement); - listener.onSuccess(url, request.getResponseText()); + + // don't load on main thread + addQueue(); + new Thread() { + public void run() { + final XMLHttpRequestWrapper request = (XMLHttpRequestWrapper)XMLHttpRequest.create(); + request.setOnreadystatechange(new EventHandlerWrapper() { + @Override + public void handleEvent(EventWrapper evt) { + if(request.getReadyState() == XMLHttpRequestWrapper.DONE) { + if(request.getStatus() != 200) { + if ((request.getStatus() != 404) && + (request.getStatus() != 403)) { + // re-try: e.g. failure due to ERR_HTTP2_SERVER_REFUSED_STREAM (too many requests) + try { + Thread.sleep(100); + } + catch (Throwable e) { + // ignored + } + loadScript(async, url, listener); + } + else { + listener.onFailure(url); + } + } + else { + if(showLog) + System.out.println("Script loaded: " + url); + NodeWrapper response = request.getResponse(); + TeaWindow currentWindow = TeaWindow.get(); + DocumentWrapper document = currentWindow.getDocument(); + HTMLElementWrapper scriptElement = document.createElement("script"); + scriptElement.appendChild(document.createTextNode(response)); + document.getBody().appendChild(scriptElement); + listener.onSuccess(url, request.getResponseText()); + } + subtractQueue(); + } } - subtractQueue(); - } + }); + setOnProgress(request, listener); + request.open("GET", url, async); + request.setRequestHeader("Content-Type", "text/plain; charset=utf-8"); + request.send(); } - }); - addQueue(); - setOnProgress(request, listener); - request.open("GET", url, async); - request.setRequestHeader("Content-Type", "text/plain; charset=utf-8"); - request.send(); + }.start(); } public void loadAudio(boolean async, final String url, final AssetLoaderListener listener) { @@ -167,34 +204,53 @@ public boolean onSuccess(String url, Blob result) { public void loadBinary(boolean async, final String url, final AssetLoaderListener listener) { if(showLog) System.out.println("Loading asset : " + url); - XMLHttpRequestWrapper request = (XMLHttpRequestWrapper)XMLHttpRequest.create(); - request.setOnreadystatechange(new EventHandlerWrapper() { - @Override - public void handleEvent(EventWrapper evt) { - if(request.getReadyState() == XMLHttpRequestWrapper.DONE) { - if(request.getStatus() != 200) { - listener.onFailure(url); - } - else { - if(showLog) - System.out.println("Asset loaded: " + url); - ArrayBufferWrapper response = (ArrayBufferWrapper)request.getResponse(); - Int8ArrayWrapper data = TypedArrays.getInstance().createInt8Array(response); - listener.onSuccess(url, new Blob(response, data)); + // don't load on main thread + addQueue(); + new Thread() { + public void run() { + XMLHttpRequestWrapper request = (XMLHttpRequestWrapper)XMLHttpRequest.create(); + request.setOnreadystatechange(new EventHandlerWrapper() { + @Override + public void handleEvent(EventWrapper evt) { + if(request.getReadyState() == XMLHttpRequestWrapper.DONE) { + if(request.getStatus() != 200) { + if ((request.getStatus() != 404) && + (request.getStatus() != 403)) { + // re-try: e.g. failure due to ERR_HTTP2_SERVER_REFUSED_STREAM (too many requests) + try { + Thread.sleep(100); + } + catch (Throwable e) { + // ignored + } + loadBinary(async, url, listener); + } + else { + listener.onFailure(url); + } + } + else { + if(showLog) + System.out.println("Asset loaded: " + url); + + ArrayBufferWrapper response = (ArrayBufferWrapper)request.getResponse(); + Int8ArrayWrapper data = TypedArrays.getInstance().createInt8Array(response); + listener.onSuccess(url, new Blob(response, data)); + } + subtractQueue(); + } } - subtractQueue(); + }); + + setOnProgress(request, listener); + request.open("GET", url, async); + if(async) { + request.setResponseType("arraybuffer"); } + request.send(); } - }); - - addQueue(); - setOnProgress(request, listener); - request.open("GET", url, async); - if(async) { - request.setResponseType("arraybuffer"); - } - request.send(); + }.start(); } public void loadImage(boolean async, final String url, final String mimeType, @@ -204,7 +260,6 @@ public void loadImage(boolean async, final String url, final String mimeType, public void loadImage(boolean async, final String url, final String mimeType, final String crossOrigin, final AssetLoaderListener listener) { - boolean isUseInlineBase64 = false; loadBinary(async, url, new AssetLoaderListener() { @Override public void onProgress(double amount) { @@ -235,7 +290,7 @@ public void handleEvent(EventWrapper evt) { subtractQueue(); } }); - if(isUseInlineBase64) { + if(useInlineBase64) { image.setSrc("data:" + mimeType + ";base64," + result.toBase64()); } else { diff --git a/backends/backend-teavm/src/main/resources/webapp/index.html b/backends/backend-teavm/src/main/resources/webapp/index.html index e546e3e0..128ce992 100644 --- a/backends/backend-teavm/src/main/resources/webapp/index.html +++ b/backends/backend-teavm/src/main/resources/webapp/index.html @@ -8,8 +8,10 @@ justify-content: center; align-items: center; background: #000; - display: flex; height: 100vh; + margin: 0; + padding: 0; + overflow: hidden } #progress { position: fixed; @@ -49,7 +51,7 @@ } - +
%LOGO% diff --git a/build.gradle b/build.gradle index 4f7fbe9b..da7c6b33 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,5 @@ apply from: 'dependencies.gradle' -buildscript { - repositories { - } - - dependencies { - } -} - allprojects { apply plugin: 'maven-publish' apply plugin: 'java' diff --git a/dependencies.gradle b/dependencies.gradle index 1c621d38..8e810f30 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,8 +1,8 @@ project.ext { groupId = "com.github.xpenatan.gdx-teavm" - var isRelease = repoUser = System.getenv('RELEASE') + var isRelease = System.getenv('RELEASE') if(isRelease != null && isRelease.toBoolean()) { - gdxTeaVMVersion = "1.0.0-b3" + gdxTeaVMVersion = "1.0.0-b4" } else { gdxTeaVMVersion = "1.0.0-SNAPSHOT" diff --git a/examples/core/core/build.gradle b/examples/core/core/build.gradle index 94fce31a..815182f6 100644 --- a/examples/core/core/build.gradle +++ b/examples/core/core/build.gradle @@ -7,5 +7,7 @@ dependencies { implementation "com.badlogicgames.gdx:gdx-box2d:$project.gdxVersion" implementation "com.badlogicgames.gdx:gdx-freetype:$project.gdxVersion" implementation "com.badlogicgames.gdx:gdx-ai:$project.aiVersion" + + implementation "net.onedaybeard.artemis:artemis-odb:2.3.0" } diff --git a/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/AITest.java b/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/AITest.java deleted file mode 100644 index 8a04f098..00000000 --- a/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/AITest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.xpenatan.gdx.examples.tests; - -import com.badlogic.gdx.ApplicationAdapter; - -public class AITest extends ApplicationAdapter { - - @Override - public void create() { - - - } -} \ No newline at end of file diff --git a/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/ArtemisTest.java b/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/ArtemisTest.java new file mode 100644 index 00000000..cf04e0b6 --- /dev/null +++ b/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/ArtemisTest.java @@ -0,0 +1,19 @@ +package com.github.xpenatan.gdx.examples.tests; + +import com.artemis.World; +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; + +public class ArtemisTest extends ApplicationAdapter { + + private AssetManager mAssetManager; + private World mEngine; + + @Override + public void create() { + mAssetManager = new AssetManager(); + mAssetManager.load("skin/skin.json", Skin.class); + mAssetManager.finishLoading(); + } +} \ No newline at end of file diff --git a/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/ReflectionTest.java b/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/ReflectionTest.java new file mode 100644 index 00000000..60d11040 --- /dev/null +++ b/examples/core/core/src/main/java/com/github/xpenatan/gdx/examples/tests/ReflectionTest.java @@ -0,0 +1,91 @@ +package com.github.xpenatan.gdx.examples.tests; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.reflect.ArrayReflection; +import com.badlogic.gdx.utils.reflect.ClassReflection; +import com.badlogic.gdx.utils.reflect.Constructor; +import com.badlogic.gdx.utils.reflect.Field; +import com.badlogic.gdx.utils.reflect.Method; + +public class ReflectionTest extends ApplicationAdapter { + String message = ""; + BitmapFont font; + SpriteBatch batch; + + @Override + public void create () { + font = new BitmapFont(); + batch = new SpriteBatch(); + + try { + Vector2 fromDefaultConstructor = ClassReflection.newInstance(Vector2.class); + Method mSet = ClassReflection.getMethod(Vector2.class, "set", float.class, float.class); + + //TODO BUG NOTE: There is a bug with teavm where the invoke args needs to have the same type as the method parameter. + //TODO Ex: calling 10 and 11 as a integer will fail because vector2.set params is float. + + mSet.invoke(fromDefaultConstructor, 10f, 11f); + println("Set to 10/11: " + fromDefaultConstructor); + Constructor copyConstroctor = ClassReflection.getConstructor(Vector2.class, Vector2.class); + Vector2 fromCopyConstructor = (Vector2)copyConstroctor.newInstance(fromDefaultConstructor); + println("From copy constructor: " + fromCopyConstructor); + + Method mMul = ClassReflection.getMethod(Vector2.class, "scl", float.class); + println("Multiplied by 2; " + mMul.invoke(fromCopyConstructor, 2f)); + + Method mNor = ClassReflection.getMethod(Vector2.class, "nor"); + println("Normalized: " + mNor.invoke(fromCopyConstructor)); + + Vector2 fieldCopy = new Vector2(); + Field fx = ClassReflection.getField(Vector2.class, "x"); + Field fy = ClassReflection.getField(Vector2.class, "y"); + fx.set(fieldCopy, fx.get(fromCopyConstructor)); + fy.set(fieldCopy, fy.get(fromCopyConstructor)); + println("Copied field by field: " + fieldCopy); + + Json json = new Json(); + String jsonString = json.toJson(fromCopyConstructor); + Vector2 fromJson = json.fromJson(Vector2.class, jsonString); + println("JSON serialized: " + jsonString); + println("JSON deserialized: " + fromJson); + fromJson.x += 1; + fromJson.y += 1; + println("JSON deserialized + 1/1: " + fromJson); + + Object array = ArrayReflection.newInstance(int.class, 5); + ArrayReflection.set(array, 0, 42); + println("Array int: length=" + ArrayReflection.getLength(array) + ", access=" + ArrayReflection.get(array, 0)); + + array = ArrayReflection.newInstance(String.class, 5); + ArrayReflection.set(array, 0, "test string"); + println("Array String: length=" + ArrayReflection.getLength(array) + ", access=" + ArrayReflection.get(array, 0)); + } catch (Exception e) { + message += "FAILED: " + e.getMessage() + "\n"; + message += e.getClass(); + } + } + + private void println (String line) { + message += line + "\n"; + } + + @Override + public void render () { + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + batch.begin(); + font.draw(batch, message, 20, Gdx.graphics.getHeight() - 20); + batch.end(); + } + + @Override + public void dispose () { + batch.dispose(); + font.dispose(); + } +} \ No newline at end of file diff --git a/examples/core/teavm/build.gradle b/examples/core/teavm/build.gradle index 936cedb3..208a36f8 100644 --- a/examples/core/teavm/build.gradle +++ b/examples/core/teavm/build.gradle @@ -37,21 +37,21 @@ task runCoreGearsDemo(dependsOn: [':examples:core:teavm:clean', ':examples:core: runCoreGearsDemo.shouldRunAfter ":examples:core:teavm:clean" -project.ext.aiTestMainClassName = "com.github.xpenatan.gdx.examples.teavm.BuildAITest" +project.ext.artemisTestMainClassName = "com.github.xpenatan.gdx.examples.teavm.BuildArtemisTest" -task buildExampleCoreAITest(dependsOn: classes, type: JavaExec) { +task buildExampleCoreArtemisTest(dependsOn: classes, type: JavaExec) { setGroup("teavm") - setDescription("Build teavm AITest example") - mainClass.set(project.aiTestMainClassName) + setDescription("Build teavm ArtemisTest example") + mainClass.set(project.artemisTestMainClassName) setClasspath(sourceSets.main.runtimeClasspath) } -task runCoreAITest(dependsOn: [':examples:core:teavm:clean', ':examples:core:teavm:buildExampleCoreAITest', ':examples:core:teavm:jettyRun']) { +task runCoreArtemisTest(dependsOn: [':examples:core:teavm:clean', ':examples:core:teavm:buildExampleCoreArtemisTest', ':examples:core:teavm:jettyRun']) { setGroup("examples-teavm") - setDescription("Run AITest example") + setDescription("Run ArtemisTest example") } -runCoreAITest.shouldRunAfter ":examples:core:teavm:clean" +runCoreArtemisTest.shouldRunAfter ":examples:core:teavm:clean" project.ext.loadingTestMainClassName = "com.github.xpenatan.gdx.examples.teavm.BuildLoadingTest" @@ -67,4 +67,20 @@ task runCoreLoadingTest(dependsOn: [':examples:core:teavm:clean', ':examples:cor setDescription("Run LoadingTest example") } -runCoreLoadingTest.shouldRunAfter ":examples:core:teavm:clean" \ No newline at end of file +runCoreLoadingTest.shouldRunAfter ":examples:core:teavm:clean" + +project.ext.reflectionTestMainClassName = "com.github.xpenatan.gdx.examples.teavm.BuildReflectionTest" + +task buildExampleCoreReflectionTest(dependsOn: classes, type: JavaExec) { + setGroup("teavm") + setDescription("Build teavm ReflecitonTest example") + mainClass.set(project.reflectionTestMainClassName) + setClasspath(sourceSets.main.runtimeClasspath) +} + +task runCoreReflecitonTest(dependsOn: [':examples:core:teavm:clean', ':examples:core:teavm:buildExampleCoreReflectionTest', ':examples:core:teavm:jettyRun']) { + setGroup("examples-teavm") + setDescription("Run Refleciton example") +} + +runCoreReflecitonTest.shouldRunAfter ":examples:core:teavm:clean" \ No newline at end of file diff --git a/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildAITest.java b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildArtemisTest.java similarity index 86% rename from examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildAITest.java rename to examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildArtemisTest.java index d1e50578..c3bbd29a 100644 --- a/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildAITest.java +++ b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildArtemisTest.java @@ -4,13 +4,13 @@ import com.github.xpenatan.gdx.backends.teavm.TeaBuilder; import com.github.xpenatan.gdx.backends.teavm.plugins.TeaReflectionSupplier; import com.github.xpenatan.gdx.backends.teavm.gen.SkipClass; -import com.github.xpenatan.gdx.examples.tests.AITest; +import com.github.xpenatan.gdx.examples.tests.ArtemisTest; import java.io.File; import java.io.IOException; import org.teavm.tooling.TeaVMTool; @SkipClass -public class BuildAITest { +public class BuildArtemisTest { public static void main(String[] args) throws IOException { String reflectionPackage = "com.badlogic.gdx.math"; @@ -20,7 +20,7 @@ public static void main(String[] args) throws IOException { TeaBuildConfiguration teaBuildConfiguration = new TeaBuildConfiguration(); teaBuildConfiguration.assetsPath.add(new File("../desktop/assets")); teaBuildConfiguration.webappPath = new File("build/dist").getCanonicalPath(); - teaBuildConfiguration.setApplicationListener(AITest.class); + teaBuildConfiguration.setApplicationListener(ArtemisTest.class); TeaVMTool tool = TeaBuilder.config(teaBuildConfiguration); tool.setObfuscated(false); TeaBuilder.build(tool); diff --git a/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildGearsDemo.java b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildGearsDemo.java index f2aa77e5..6303724e 100644 --- a/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildGearsDemo.java +++ b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildGearsDemo.java @@ -3,7 +3,7 @@ import com.github.xpenatan.gdx.backends.teavm.TeaBuildConfiguration; import com.github.xpenatan.gdx.backends.teavm.TeaBuilder; import com.github.xpenatan.gdx.backends.teavm.gen.SkipClass; -import com.github.xpenatan.gdx.examples.tests.GearsDemo; +import com.github.xpenatan.gdx.examples.teavm.launcher.GearsTestLauncher; import java.io.File; import java.io.IOException; import org.teavm.tooling.TeaVMTool; @@ -15,9 +15,10 @@ public static void main(String[] args) throws IOException { TeaBuildConfiguration teaBuildConfiguration = new TeaBuildConfiguration(); teaBuildConfiguration.assetsPath.add(new File("../desktop/assets")); teaBuildConfiguration.webappPath = new File("build/dist").getCanonicalPath(); - teaBuildConfiguration.setApplicationListener(GearsDemo.class); + TeaVMTool tool = TeaBuilder.config(teaBuildConfiguration); tool.setObfuscated(false); + tool.setMainClass(GearsTestLauncher.class.getName()); TeaBuilder.build(tool); } } diff --git a/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildReflectionTest.java b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildReflectionTest.java new file mode 100644 index 00000000..d2241d68 --- /dev/null +++ b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/BuildReflectionTest.java @@ -0,0 +1,27 @@ +package com.github.xpenatan.gdx.examples.teavm; + +import com.github.xpenatan.gdx.backends.teavm.TeaBuildConfiguration; +import com.github.xpenatan.gdx.backends.teavm.TeaBuilder; +import com.github.xpenatan.gdx.backends.teavm.plugins.TeaReflectionSupplier; +import com.github.xpenatan.gdx.backends.teavm.gen.SkipClass; +import com.github.xpenatan.gdx.examples.tests.ReflectionTest; +import java.io.File; +import java.io.IOException; +import org.teavm.tooling.TeaVMTool; + +@SkipClass +public class BuildReflectionTest { + + public static void main(String[] args) throws IOException { + String reflectionPackage = "com.badlogic.gdx.math"; + TeaReflectionSupplier.addReflectionClass(reflectionPackage); + + TeaBuildConfiguration teaBuildConfiguration = new TeaBuildConfiguration(); + teaBuildConfiguration.assetsPath.add(new File("../desktop/assets")); + teaBuildConfiguration.webappPath = new File("build/dist").getCanonicalPath(); + teaBuildConfiguration.obfuscate = false; + teaBuildConfiguration.setApplicationListener(ReflectionTest.class); + TeaVMTool tool = TeaBuilder.config(teaBuildConfiguration); + TeaBuilder.build(tool); + } +} diff --git a/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/launcher/GearsTestLauncher.java b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/launcher/GearsTestLauncher.java new file mode 100644 index 00000000..e7f52f05 --- /dev/null +++ b/examples/core/teavm/src/main/java/com/github/xpenatan/gdx/examples/teavm/launcher/GearsTestLauncher.java @@ -0,0 +1,15 @@ +package com.github.xpenatan.gdx.examples.teavm.launcher; + +import com.github.xpenatan.gdx.backends.teavm.TeaApplication; +import com.github.xpenatan.gdx.backends.teavm.TeaApplicationConfiguration; +import com.github.xpenatan.gdx.examples.tests.GearsDemo; + +public class GearsTestLauncher { + + public static void main(String[] args) { + TeaApplicationConfiguration config = new TeaApplicationConfiguration("canvas"); + config.width = 0; + config.height = 0; + new TeaApplication(new GearsDemo(), config); + } +} \ No newline at end of file