mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-27 10:28:14 -05:00
Update #52 - Fixed various issues with the client
This commit is contained in:
@ -162,6 +162,8 @@ The default eaglercraftXOpts values is this:
|
||||
- `singleThreadMode:` if the game should run the client and integrated server in the same context instead of creating a worker object
|
||||
- `enableEPKVersionCheck:` if the game should attempt to bypass the browser's cache and retry downloading assets.epk when its outdated
|
||||
- `enforceVSync:` (WASM only) if the game should automatically re-enable VSync at launch if its disabled
|
||||
- `keepAliveHack:` if the game should embed a looping `<audio>` tag to keep the tab from becoming inactive on Chrome
|
||||
- `finishOnSwap:` if the WebGL `finish` function should be called after every frame when VSync is disabled
|
||||
- `hooks:` can be used to define JavaScript callbacks for certain events
|
||||
* `localStorageSaved:` JavaScript callback to save local storage keys (key, data)
|
||||
* `localStorageLoaded:` JavaScript callback to load local storage keys (key) returns data
|
||||
|
@ -1 +1 @@
|
||||
u51
|
||||
u52
|
@ -21,7 +21,17 @@
|
||||
~ import net.lax1dude.eaglercraft.v1_8.netty.ByteBufInputStream;
|
||||
~ import net.lax1dude.eaglercraft.v1_8.netty.ByteBufOutputStream;
|
||||
|
||||
> CHANGE 98 : 99 @ 98 : 99
|
||||
> CHANGE 30 : 37 @ 30 : 32
|
||||
|
||||
~ public byte[] readByteArray(int maxLen) {
|
||||
~ int i = this.readVarIntFromBuffer();
|
||||
~ if (i < 0 || i > maxLen) {
|
||||
~ throw new DecoderException(
|
||||
~ "The received array length is longer than maximum allowed (" + i + " > " + maxLen + ")");
|
||||
~ }
|
||||
~ byte[] abyte = new byte[i];
|
||||
|
||||
> CHANGE 66 : 67 @ 66 : 67
|
||||
|
||||
~ public void writeUuid(EaglercraftUUID uuid) {
|
||||
|
||||
|
@ -35,9 +35,9 @@
|
||||
> CHANGE 3 : 8 @ 3 : 4
|
||||
|
||||
~ this.profile = new GameProfile((EaglercraftUUID) null, parPacketBuffer.readStringFromBuffer(16));
|
||||
~ this.skin = parPacketBuffer.readByteArray();
|
||||
~ this.cape = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readByteArray() : null;
|
||||
~ this.protocols = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readByteArray() : null;
|
||||
~ this.skin = parPacketBuffer.readByteArray(32768);
|
||||
~ this.cape = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readByteArray(32768) : null;
|
||||
~ this.protocols = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readByteArray(256) : null;
|
||||
~ this.brandUUID = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readUuid() : null;
|
||||
|
||||
> INSERT 4 : 8 @ 4
|
||||
|
@ -18,7 +18,12 @@
|
||||
~ // this.verifyTokenEncrypted = CryptManager.encryptData(publicKey, verifyToken);
|
||||
~ // }
|
||||
|
||||
> CHANGE 15 : 18 @ 15 : 18
|
||||
> CHANGE 2 : 4 @ 2 : 4
|
||||
|
||||
~ this.secretKeyEncrypted = parPacketBuffer.readByteArray(1024);
|
||||
~ this.verifyTokenEncrypted = parPacketBuffer.readByteArray(1024);
|
||||
|
||||
> CHANGE 11 : 14 @ 11 : 14
|
||||
|
||||
~ // public SecretKey getSecretKey(PrivateKey key) {
|
||||
~ // return CryptManager.decryptSharedKey(key, this.secretKeyEncrypted);
|
||||
|
@ -23,13 +23,14 @@
|
||||
~ // this.verifyToken = verifyToken;
|
||||
~ // }
|
||||
|
||||
> CHANGE 3 : 6 @ 3 : 4
|
||||
> CHANGE 3 : 7 @ 3 : 5
|
||||
|
||||
~ // this.publicKey =
|
||||
~ // CryptManager.decodePublicKey(parPacketBuffer.readByteArray());
|
||||
~ parPacketBuffer.readByteArray(); // skip
|
||||
~ parPacketBuffer.readByteArray(1024); // skip
|
||||
~ this.verifyToken = parPacketBuffer.readByteArray(1024);
|
||||
|
||||
> CHANGE 4 : 7 @ 4 : 7
|
||||
> CHANGE 3 : 6 @ 3 : 6
|
||||
|
||||
~ // parPacketBuffer.writeString(this.hashedServerId);
|
||||
~ // parPacketBuffer.writeByteArray(this.publicKey.getEncoded());
|
||||
|
@ -17,7 +17,11 @@
|
||||
|
||||
+ chunkIn.alfheim$getLightingEngine().processLightUpdates();
|
||||
|
||||
> CHANGE 40 : 41 @ 40 : 41
|
||||
> CHANGE 9 : 10 @ 9 : 10
|
||||
|
||||
~ this.extractedData.data = parPacketBuffer.readByteArray(0x1000000);
|
||||
|
||||
> CHANGE 30 : 31 @ 30 : 31
|
||||
|
||||
~ ArrayList<ExtendedBlockStorage> arraylist = Lists.newArrayList();
|
||||
|
||||
|
@ -9,7 +9,11 @@
|
||||
|
||||
+
|
||||
|
||||
> CHANGE 64 : 66 @ 64 : 65
|
||||
> CHANGE 54 : 55 @ 54 : 55
|
||||
|
||||
~ this.mapDataBytes = parPacketBuffer.readByteArray(0x400000);
|
||||
|
||||
> CHANGE 9 : 11 @ 9 : 10
|
||||
|
||||
~ for (int i = 0; i < this.mapVisiblePlayersVec4b.length; ++i) {
|
||||
~ Vec4b vec4b = this.mapVisiblePlayersVec4b[i];
|
||||
|
@ -265,7 +265,7 @@
|
||||
+ eaglercraft.command.clientStub=This command is client side!
|
||||
+
|
||||
|
||||
> INSERT 163 : 578 @ 163
|
||||
> INSERT 163 : 574 @ 163
|
||||
|
||||
+ eaglercraft.singleplayer.busy.killTask=Cancel Task
|
||||
+ eaglercraft.singleplayer.busy.cancelWarning=Are you sure?
|
||||
@ -656,11 +656,7 @@
|
||||
+ eaglercraft.options.badVideoSettingsDetected.title=Issues Detected
|
||||
+ eaglercraft.options.badVideoSettingsDetected.0=Some of your video settings may be causing
|
||||
+ eaglercraft.options.badVideoSettingsDetected.1=the game to lag excessively
|
||||
+ eaglercraft.options.badVideoSettingsDetected.vsync.0=VSync is disabled, some browsers require
|
||||
+ eaglercraft.options.badVideoSettingsDetected.vsync.1=VSync to be enabled to hint when the
|
||||
+ eaglercraft.options.badVideoSettingsDetected.vsync.2=framebuffer has updated. If the game feels
|
||||
+ eaglercraft.options.badVideoSettingsDetected.vsync.3=significantly slower than is indicated by
|
||||
+ eaglercraft.options.badVideoSettingsDetected.vsync.4=the FPS counter, you should enable VSync.
|
||||
+ eaglercraft.options.badVideoSettingsDetected.vsync.0=VSync is disabled, this may cause input lag
|
||||
+ eaglercraft.options.badVideoSettingsDetected.renderDistance.0=Render distance is %d chunks, most devices
|
||||
+ eaglercraft.options.badVideoSettingsDetected.renderDistance.1=lag when the render distance is greater
|
||||
+ eaglercraft.options.badVideoSettingsDetected.renderDistance.2=than 4 chunks
|
||||
|
@ -125,7 +125,7 @@ public class EaglerLWJGLFloatBuffer extends FloatBuffer {
|
||||
@Override
|
||||
public FloatBuffer get(float[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset, address + (position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
@ -161,7 +161,7 @@ public class EaglerLWJGLFloatBuffer extends FloatBuffer {
|
||||
@Override
|
||||
public FloatBuffer put(float[] src, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class EaglerLWJGLIntBuffer extends IntBuffer {
|
||||
@Override
|
||||
public IntBuffer get(int[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset, address + (position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
@ -161,7 +161,7 @@ public class EaglerLWJGLIntBuffer extends IntBuffer {
|
||||
@Override
|
||||
public IntBuffer put(int[] src, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class EaglerLWJGLShortBuffer extends ShortBuffer {
|
||||
@Override
|
||||
public ShortBuffer get(short[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset, address + (position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
@ -161,7 +161,7 @@ public class EaglerLWJGLShortBuffer extends ShortBuffer {
|
||||
@Override
|
||||
public ShortBuffer put(short[] src, int offset, int length) {
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ public class EaglercraftVersion {
|
||||
/// Customize these to fit your fork:
|
||||
|
||||
public static final String projectForkName = "EaglercraftX";
|
||||
public static final String projectForkVersion = "u51";
|
||||
public static final String projectForkVersion = "u52";
|
||||
public static final String projectForkVendor = "lax1dude";
|
||||
|
||||
public static final String projectForkURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8";
|
||||
@ -20,20 +20,20 @@ public class EaglercraftVersion {
|
||||
public static final String projectOriginName = "EaglercraftX";
|
||||
public static final String projectOriginAuthor = "lax1dude";
|
||||
public static final String projectOriginRevision = "1.8";
|
||||
public static final String projectOriginVersion = "u51";
|
||||
public static final String projectOriginVersion = "u52";
|
||||
|
||||
public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace
|
||||
|
||||
// EPK Version Identifier
|
||||
|
||||
public static final String EPKVersionIdentifier = "u51"; // Set to null to disable EPK version check
|
||||
public static final String EPKVersionIdentifier = "u52"; // Set to null to disable EPK version check
|
||||
|
||||
// Updating configuration
|
||||
|
||||
public static final boolean enableUpdateService = true;
|
||||
|
||||
public static final String updateBundlePackageName = "net.lax1dude.eaglercraft.v1_8.client";
|
||||
public static final int updateBundlePackageVersionInt = 51;
|
||||
public static final int updateBundlePackageVersionInt = 52;
|
||||
|
||||
public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName;
|
||||
|
||||
|
@ -30,7 +30,7 @@ public class GuiScreenVSyncReEnabled extends GuiScreen {
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 136, I18n.format("options.vsyncReEnabled.continue")));
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 142, I18n.format("options.vsyncReEnabled.continue")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
|
@ -49,10 +49,6 @@ public class GuiScreenVideoSettingsWarning extends GuiScreen {
|
||||
if((mask & WARNING_VSYNC) != 0) {
|
||||
messages.add(null);
|
||||
messages.add(I18n.format("options.badVideoSettingsDetected.vsync.0"));
|
||||
messages.add(I18n.format("options.badVideoSettingsDetected.vsync.1"));
|
||||
messages.add(I18n.format("options.badVideoSettingsDetected.vsync.2"));
|
||||
messages.add(I18n.format("options.badVideoSettingsDetected.vsync.3"));
|
||||
messages.add(I18n.format("options.badVideoSettingsDetected.vsync.4"));
|
||||
}
|
||||
if((mask & WARNING_RENDER_DISTANCE) != 0) {
|
||||
messages.add(null);
|
||||
|
@ -63,13 +63,13 @@ public class EaglerMeshLoader implements IResourceManagerReloadListener {
|
||||
int intsOfVertex, intsOfIndex, intsTotal, stride;
|
||||
try(DataInputStream dis = new DataInputStream(resourceManager.getResource(meshLoc).getInputStream())) {
|
||||
byte[] header = new byte[8];
|
||||
dis.read(header);
|
||||
dis.readFully(header);
|
||||
if(!Arrays.equals(header, new byte[] { (byte) 33, (byte) 69, (byte) 65, (byte) 71, (byte) 36,
|
||||
(byte) 109, (byte) 100, (byte) 108 })) {
|
||||
throw new IOException("File is not an eaglercraft high-poly mesh!");
|
||||
}
|
||||
|
||||
char CT = (char)dis.read();
|
||||
char CT = (char)dis.readUnsignedByte();
|
||||
|
||||
if(CT == 'C') {
|
||||
meshStruct.hasTexture = false;
|
||||
|
@ -493,27 +493,21 @@ public class EaglercraftGPU {
|
||||
}
|
||||
|
||||
public static void enableVertexAttribArray(int index) {
|
||||
if(emulatedVAOs) {
|
||||
if(currentVertexArray == null) {
|
||||
logger.warn("Skipping enable attrib with emulated VAO because no known VAO is bound!");
|
||||
return;
|
||||
}
|
||||
((SoftGLVertexArray)currentVertexArray).enableAttrib(index, true);
|
||||
}else {
|
||||
if(!emulatedVAOs) {
|
||||
_wglEnableVertexAttribArray(index);
|
||||
}
|
||||
if (currentVertexArray != null) {
|
||||
currentVertexArray.setBit(1 << index);
|
||||
}
|
||||
}
|
||||
|
||||
public static void disableVertexAttribArray(int index) {
|
||||
if(emulatedVAOs) {
|
||||
if(currentVertexArray == null) {
|
||||
logger.warn("Skipping disable attrib with emulated VAO because no known VAO is bound!");
|
||||
return;
|
||||
}
|
||||
((SoftGLVertexArray)currentVertexArray).enableAttrib(index, false);
|
||||
}else {
|
||||
if(!emulatedVAOs) {
|
||||
_wglDisableVertexAttribArray(index);
|
||||
}
|
||||
if (currentVertexArray != null) {
|
||||
currentVertexArray.unsetBit(1 << index);
|
||||
}
|
||||
}
|
||||
|
||||
public static void vertexAttribPointer(int index, int size, int format, boolean normalized, int stride, int offset) {
|
||||
|
@ -74,12 +74,15 @@ class SoftGLVertexArray implements IVertexArrayGL {
|
||||
}
|
||||
}
|
||||
|
||||
void enableAttrib(int index, boolean en) {
|
||||
if(en) {
|
||||
enabled |= (1 << index);
|
||||
}else {
|
||||
enabled &= ~(1 << index);
|
||||
}
|
||||
@Override
|
||||
public void setBit(int bit) {
|
||||
enabled |= bit;
|
||||
enabledCnt = 32 - Integer.numberOfLeadingZeros(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetBit(int bit) {
|
||||
enabled &= ~bit;
|
||||
enabledCnt = 32 - Integer.numberOfLeadingZeros(enabled);
|
||||
}
|
||||
|
||||
@ -183,6 +186,11 @@ class SoftGLVertexArray implements IVertexArrayGL {
|
||||
public void free() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBits() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static class Attrib {
|
||||
|
||||
final IBufferGL buffer;
|
||||
@ -223,17 +231,4 @@ class SoftGLVertexArray implements IVertexArrayGL {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBits() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBit(int bit) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetBit(int bit) {
|
||||
}
|
||||
|
||||
}
|
@ -42,14 +42,6 @@ public class StreamBuffer {
|
||||
|
||||
}
|
||||
|
||||
private static PoolInstance fillPoolInstance() {
|
||||
PoolInstance ret = pool[poolBufferID++];
|
||||
if(poolBufferID > poolSize - 1) {
|
||||
poolBufferID = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void resizeInstance(PoolInstance instance, int requiredMemory) {
|
||||
IBufferGL buffer = instance.vertexBuffer;
|
||||
if (buffer == null) {
|
||||
@ -67,8 +59,6 @@ public class StreamBuffer {
|
||||
|
||||
protected StreamBufferInstance[] buffers;
|
||||
|
||||
protected int currentBufferId = 0;
|
||||
|
||||
protected final IStreamBufferInitializer initializer;
|
||||
|
||||
public static class StreamBufferInstance {
|
||||
@ -94,24 +84,17 @@ public class StreamBuffer {
|
||||
}
|
||||
|
||||
public StreamBuffer(IStreamBufferInitializer initializer) {
|
||||
this(poolSize, initializer);
|
||||
}
|
||||
|
||||
public StreamBuffer(int count, IStreamBufferInitializer initializer) {
|
||||
if(count > poolSize) {
|
||||
count = poolSize;
|
||||
}
|
||||
this.buffers = new StreamBufferInstance[count];
|
||||
this.buffers = new StreamBufferInstance[poolSize];
|
||||
for(int i = 0; i < this.buffers.length; ++i) {
|
||||
StreamBufferInstance j = new StreamBufferInstance();
|
||||
j.poolInstance = fillPoolInstance();
|
||||
j.poolInstance = pool[i];
|
||||
this.buffers[i] = j;
|
||||
}
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
public StreamBufferInstance getBuffer(int requiredMemory) {
|
||||
StreamBufferInstance next = buffers[(currentBufferId++) % buffers.length];
|
||||
StreamBufferInstance next = buffers[poolBufferID++ % buffers.length];
|
||||
resizeInstance(next.poolInstance, requiredMemory);
|
||||
if(next.vertexArray == null) {
|
||||
next.vertexArray = EaglercraftGPU.createGLVertexArray();
|
||||
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred;
|
||||
|
||||
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
|
||||
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
|
||||
import static net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.ExtGLEnums.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Display;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IFramebufferGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IRenderbufferGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.DrawUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GLSLHeader;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.VSHInputLayoutParser;
|
||||
|
||||
public class D3DCmpLod0IssueCheck {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("D3DCmpLod0IssueCheck");
|
||||
|
||||
public static boolean test() {
|
||||
String rendererString = EaglercraftGPU.glGetString(GL_RENDERER);
|
||||
if (rendererString == null || !rendererString.contains(" Direct3D11 ")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.info("Checking for D3D compiler issue...");
|
||||
|
||||
String vshLocalSrc = EagRuntime.getRequiredResourceString("/assets/eagler/glsl/local.vsh");
|
||||
List<VSHInputLayoutParser.ShaderInput> vertLayout = VSHInputLayoutParser.getShaderInputs(vshLocalSrc);
|
||||
IShaderGL vert = _wglCreateShader(GL_VERTEX_SHADER);
|
||||
_wglShaderSource(vert, GLSLHeader.getVertexHeaderCompat(vshLocalSrc, DrawUtils.vertexShaderPrecision));
|
||||
_wglCompileShader(vert);
|
||||
if (_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) {
|
||||
Display.checkContextLost();
|
||||
_wglDeleteShader(vert);
|
||||
logger.error("Failed to compile vertex shader! This should not happen!");
|
||||
logger.error("Don't know how to proceed");
|
||||
return false;
|
||||
}
|
||||
|
||||
IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(frag, GLSLHeader.getHeader()
|
||||
+ EagRuntime.getRequiredResourceString("/assets/eagler/glsl/deferred/check_d3d_cmplod0.fsh"));
|
||||
_wglCompileShader(frag);
|
||||
if (_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
|
||||
Display.checkContextLost();
|
||||
logger.info(_wglGetShaderInfoLog(frag));
|
||||
_wglDeleteShader(vert);
|
||||
_wglDeleteShader(frag);
|
||||
logger.error("Failed to compile fragment shader! This should not happen!");
|
||||
logger.error("D3D compiler workarounds will be enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
IProgramGL program = _wglCreateProgram();
|
||||
|
||||
_wglAttachShader(program, vert);
|
||||
_wglAttachShader(program, frag);
|
||||
|
||||
if (EaglercraftGPU.checkOpenGLESVersion() == 200) {
|
||||
VSHInputLayoutParser.applyLayout(program, vertLayout);
|
||||
}
|
||||
|
||||
_wglLinkProgram(program);
|
||||
|
||||
_wglDetachShader(program, vert);
|
||||
_wglDetachShader(program, frag);
|
||||
_wglDeleteShader(vert);
|
||||
_wglDeleteShader(frag);
|
||||
|
||||
if (_wglGetProgrami(program, GL_LINK_STATUS) != GL_TRUE) {
|
||||
Display.checkContextLost();
|
||||
_wglDeleteProgram(program);
|
||||
logger.error("Failed to link program! This should not happen!");
|
||||
logger.error("D3D compiler workarounds will be enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
EaglercraftGPU.bindGLShaderProgram(program);
|
||||
_wglUniform1i(_wglGetUniformLocation(program, "u_inputTexture"), 0);
|
||||
|
||||
int emptyTexture = GlStateManager.generateTexture();
|
||||
GlStateManager.bindTexture(emptyTexture);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, _GL_TEXTURE_COMPARE_FUNC, GL_GREATER);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, _GL_TEXTURE_COMPARE_MODE, _GL_COMPARE_REF_TO_TEXTURE);
|
||||
_wglTexImage2D(GL_TEXTURE_2D, 0, _GL_DEPTH_COMPONENT24, 256, 256, 0, _GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, (ByteBuffer)null);
|
||||
|
||||
IFramebufferGL fbo = _wglCreateFramebuffer();
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, fbo);
|
||||
IRenderbufferGL rbo = _wglCreateRenderbuffer();
|
||||
_wglBindRenderbuffer(_GL_RENDERBUFFER, rbo);
|
||||
_wglRenderbufferStorage(_GL_RENDERBUFFER, GL_RGBA8, 256, 256);
|
||||
_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, _GL_RENDERBUFFER, rbo);
|
||||
_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
|
||||
|
||||
int err = _wglGetError();
|
||||
if (err != 0) {
|
||||
logger.error("Ignored OpenGL error while clearing error state: ", EaglercraftGPU.gluErrorString(err));
|
||||
}
|
||||
|
||||
DrawUtils.drawStandardQuad2D();
|
||||
|
||||
err = _wglGetError();
|
||||
|
||||
GlStateManager.deleteTexture(emptyTexture);
|
||||
_wglDeleteProgram(program);
|
||||
_wglDeleteRenderbuffer(rbo);
|
||||
_wglDeleteFramebuffer(fbo);
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, null);
|
||||
|
||||
if (err != 0) {
|
||||
logger.error("Using the test shader generated error: {}", EaglercraftGPU.gluErrorString(err));
|
||||
logger.error("D3D compiler workarounds will be enabled");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1889,45 +1889,9 @@ public class EaglerDeferredPipeline {
|
||||
matrixCopyBuffer.flip();
|
||||
_wglUniformMatrix4x2fv(shader_reproject_ssr.uniforms.u_lastInverseProjMatrix4x2f, false, matrixCopyBuffer);
|
||||
_wglUniform1f(shader_reproject_ssr.uniforms.u_sampleStep1f, 0.125f);
|
||||
_wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5);
|
||||
|
||||
if(shader_reproject_ssr.uniforms.u_sampleDelta1i != null) {
|
||||
_wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5);
|
||||
DrawUtils.drawStandardQuad2D();
|
||||
}else {
|
||||
DrawUtils.drawStandardQuad2D(); // sample 1
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(reprojectionSSRHitVector[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(reprojectionSSRTexture[1]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 2
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(reprojectionSSRHitVector[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(reprojectionSSRTexture[0]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 3
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(reprojectionSSRHitVector[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(reprojectionSSRTexture[1]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 4
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(reprojectionSSRHitVector[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(reprojectionSSRTexture[0]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 5
|
||||
}
|
||||
DrawUtils.drawStandardQuad2D();
|
||||
|
||||
DeferredStateManager.checkGLError("combineGBuffersAndIlluminate(): RUN SCREENSPACE REFLECTIONS ALGORITHM");
|
||||
}
|
||||
@ -2900,45 +2864,9 @@ public class EaglerDeferredPipeline {
|
||||
matrixCopyBuffer.flip();
|
||||
_wglUniformMatrix4x2fv(shader_reproject_ssr.uniforms.u_lastInverseProjMatrix4x2f, false, matrixCopyBuffer);
|
||||
_wglUniform1f(shader_reproject_ssr.uniforms.u_sampleStep1f, 0.5f);
|
||||
_wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5);
|
||||
|
||||
if(shader_reproject_ssr.uniforms.u_sampleDelta1i != null) {
|
||||
_wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5);
|
||||
DrawUtils.drawStandardQuad2D();
|
||||
}else {
|
||||
DrawUtils.drawStandardQuad2D(); // sample 1
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 2
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 3
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 4
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE3);
|
||||
GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]);
|
||||
GlStateManager.setActiveTexture(GL_TEXTURE2);
|
||||
GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]);
|
||||
|
||||
DrawUtils.drawStandardQuad2D(); // sample 5
|
||||
}
|
||||
DrawUtils.drawStandardQuad2D();
|
||||
|
||||
DeferredStateManager.checkGLError("endDrawRealisticWaterMask(): RUN SCREENSPACE REFLECTIONS ALGORITHM");
|
||||
|
||||
|
@ -28,6 +28,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.IExtPipelineCompiler;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.GBufferExtPipelineShader;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.ShaderCompiler;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.ShaderSource;
|
||||
import net.lax1dude.eaglercraft.v1_8.vector.Matrix4f;
|
||||
import net.lax1dude.eaglercraft.v1_8.vector.Vector4f;
|
||||
@ -59,6 +60,11 @@ public class GBufferPipelineCompiler implements IExtPipelineCompiler {
|
||||
userPointer[0] = new GBufferPipelineProgramInstance(stateCoreBits, stateExtBits);
|
||||
EaglerDeferredConfig conf = Minecraft.getMinecraft().gameSettings.deferredShaderConf;
|
||||
StringBuilder macros = new StringBuilder();
|
||||
if (ShaderCompiler.isBrokenD3DCompiler()) {
|
||||
macros.append("#define CMPLOD0_D3D_WORKAROUND(a, b) texture(a, b)\n");
|
||||
} else {
|
||||
macros.append("#define CMPLOD0_D3D_WORKAROUND(a, b) textureLod(a, b, 0.0)\n");
|
||||
}
|
||||
if((stateExtBits & STATE_SHADOW_RENDER) != 0) {
|
||||
if((stateExtBits & STATE_CLIP_PLANE) != 0) {
|
||||
macros.append("#define STATE_CLIP_PLANE\n");
|
||||
|
@ -186,12 +186,12 @@ public class LensFlareMeshRenderer {
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
_wglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
int mip = 0;
|
||||
while(dis.read() == 'E') {
|
||||
while(dis.readUnsignedByte() == 'E') {
|
||||
int w = dis.readShort();
|
||||
int h = dis.readShort();
|
||||
copyBuffer.clear();
|
||||
for(int i = 0, l = w * h; i < l; ++i) {
|
||||
copyBuffer.put((byte)dis.read());
|
||||
copyBuffer.put((byte)dis.readUnsignedByte());
|
||||
}
|
||||
copyBuffer.flip();
|
||||
_wglTexImage2D(GL_TEXTURE_2D, mip++, _GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, copyBuffer);
|
||||
|
@ -54,18 +54,19 @@ public class LightSourceMesh {
|
||||
destroy();
|
||||
try (DataInputStream is = new DataInputStream(
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(meshLocation).getInputStream())) {
|
||||
if(is.read() != 0xEE || is.read() != 0xAA || is.read() != 0x66 || is.read() != '%') {
|
||||
if(is.readUnsignedByte() != 0xEE || is.readUnsignedByte() != 0xAA || is.readUnsignedByte() != 0x66
|
||||
|| is.readUnsignedByte() != '%') {
|
||||
throw new IOException("Bad file type for: " + meshLocation.toString());
|
||||
}
|
||||
byte[] bb = new byte[is.read()];
|
||||
is.read(bb);
|
||||
byte[] bb = new byte[is.readUnsignedByte()];
|
||||
is.readFully(bb);
|
||||
if(!Arrays.equals(bb, typeBytes)) {
|
||||
throw new IOException("Bad file type \"" + new String(bb, StandardCharsets.UTF_8) + "\" for: " + meshLocation.toString());
|
||||
}
|
||||
|
||||
int vboLength = is.readInt() * 6;
|
||||
byte[] readBuffer = new byte[vboLength];
|
||||
is.read(readBuffer);
|
||||
is.readFully(readBuffer);
|
||||
|
||||
ByteBuffer buf = EagRuntime.allocateByteBuffer(readBuffer.length);
|
||||
buf.put(readBuffer);
|
||||
@ -78,7 +79,7 @@ public class LightSourceMesh {
|
||||
EagRuntime.freeByteBuffer(buf);
|
||||
|
||||
int iboLength = meshIndexCount = is.readInt();
|
||||
int iboType = is.read();
|
||||
int iboType = is.readUnsignedByte();
|
||||
iboLength *= iboType;
|
||||
switch(iboType) {
|
||||
case 1:
|
||||
@ -95,7 +96,7 @@ public class LightSourceMesh {
|
||||
}
|
||||
|
||||
readBuffer = new byte[iboLength];
|
||||
is.read(readBuffer);
|
||||
is.readFully(readBuffer);
|
||||
|
||||
buf = EagRuntime.allocateByteBuffer(readBuffer.length);
|
||||
buf.put(readBuffer);
|
||||
|
@ -63,18 +63,19 @@ public class SkyboxRenderer {
|
||||
destroy();
|
||||
try (DataInputStream is = new DataInputStream(
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(skyboxLocation).getInputStream())) {
|
||||
if(is.read() != 0xEE || is.read() != 0xAA || is.read() != 0x66 || is.read() != '%') {
|
||||
if(is.readUnsignedByte() != 0xEE || is.readUnsignedByte() != 0xAA || is.readUnsignedByte() != 0x66
|
||||
|| is.readUnsignedByte() != '%') {
|
||||
throw new IOException("Bad file type for: " + skyboxLocation.toString());
|
||||
}
|
||||
byte[] bb = new byte[is.read()];
|
||||
is.read(bb);
|
||||
is.readFully(bb);
|
||||
if(!Arrays.equals(bb, new byte[] { 's', 'k', 'y', 'b', 'o', 'x' })) {
|
||||
throw new IOException("Bad file type \"" + new String(bb, StandardCharsets.UTF_8) + "\" for: " + skyboxLocation.toString());
|
||||
}
|
||||
atmosphereLUTWidth = is.readUnsignedShort();
|
||||
atmosphereLUTHeight = is.readUnsignedShort();
|
||||
byte[] readBuffer = new byte[atmosphereLUTWidth * atmosphereLUTHeight * 4];
|
||||
is.read(readBuffer);
|
||||
is.readFully(readBuffer);
|
||||
|
||||
ByteBuffer buf = EagRuntime.allocateByteBuffer(readBuffer.length);
|
||||
buf.put(readBuffer);
|
||||
@ -97,7 +98,7 @@ public class SkyboxRenderer {
|
||||
|
||||
int vboLength = is.readInt() * 8;
|
||||
readBuffer = new byte[vboLength];
|
||||
is.read(readBuffer);
|
||||
is.readFully(readBuffer);
|
||||
|
||||
buf = EagRuntime.allocateByteBuffer(readBuffer.length);
|
||||
buf.put(readBuffer);
|
||||
@ -110,7 +111,7 @@ public class SkyboxRenderer {
|
||||
EagRuntime.freeByteBuffer(buf);
|
||||
|
||||
int iboLength = skyboxIndexCount = is.readInt();
|
||||
int iboType = is.read();
|
||||
int iboType = is.readUnsignedByte();
|
||||
iboLength *= iboType;
|
||||
switch(iboType) {
|
||||
case 1:
|
||||
@ -129,7 +130,7 @@ public class SkyboxRenderer {
|
||||
skyboxIndexStride = iboType;
|
||||
|
||||
readBuffer = new byte[iboLength];
|
||||
is.read(readBuffer);
|
||||
is.readFully(readBuffer);
|
||||
|
||||
buf = EagRuntime.allocateByteBuffer(readBuffer.length);
|
||||
buf.put(readBuffer);
|
||||
|
@ -28,12 +28,27 @@ import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GLSLHeader;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.D3DCmpLod0IssueCheck;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class ShaderCompiler {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("DeferredPipelineCompiler");
|
||||
|
||||
private static boolean isBrokenD3DCompiler = false;
|
||||
private static boolean isBrokenD3DChecked = false;
|
||||
|
||||
/**
|
||||
* Warning: binds a different framebuffer
|
||||
*/
|
||||
public static boolean isBrokenD3DCompiler() {
|
||||
if (!isBrokenD3DChecked) {
|
||||
isBrokenD3DCompiler = D3DCmpLod0IssueCheck.test();
|
||||
isBrokenD3DChecked = true;
|
||||
}
|
||||
return isBrokenD3DCompiler;
|
||||
}
|
||||
|
||||
public static IShaderGL compileShader(String name, int stage, ResourceLocation filename, String... compileFlags) throws ShaderCompileException {
|
||||
String src = ShaderSource.getSourceFor(filename);
|
||||
if(src == null) {
|
||||
@ -58,7 +73,13 @@ public class ShaderCompiler {
|
||||
logger.info("Compiling Shader: " + filename);
|
||||
StringBuilder srcCat = new StringBuilder();
|
||||
srcCat.append(GLSLHeader.getHeader()).append('\n');
|
||||
|
||||
|
||||
if (isBrokenD3DCompiler()) {
|
||||
srcCat.append("#define CMPLOD0_D3D_WORKAROUND(a, b) texture(a, b)\n");
|
||||
} else {
|
||||
srcCat.append("#define CMPLOD0_D3D_WORKAROUND(a, b) textureLod(a, b, 0.0)\n");
|
||||
}
|
||||
|
||||
if(compileFlags != null && compileFlags.size() > 0) {
|
||||
for(int i = 0, l = compileFlags.size(); i < l; ++i) {
|
||||
srcCat.append("#define ").append(compileFlags.get(i)).append('\n');
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023 lax1dude. All Rights Reserved.
|
||||
* Copyright (c) 2023-2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@ -34,53 +35,72 @@ public class EaglerBitwisePackedTexture {
|
||||
}
|
||||
}
|
||||
|
||||
public static ImageData loadTexture(InputStream is, int alpha) throws IOException {
|
||||
if(is.read() != '%' || is.read() != 'E' || is.read() != 'B' || is.read() != 'P') {
|
||||
private static int readByte(InputStream is) throws IOException {
|
||||
int i = is.read();
|
||||
if (i < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public static ImageData loadTexture(InputStream is) throws IOException {
|
||||
if(readByte(is) != '%' || readByte(is) != 'E' || readByte(is) != 'B' || readByte(is) != 'P') {
|
||||
throw new IOException("Not an EBP file!");
|
||||
}
|
||||
int v = is.read();
|
||||
int v = readByte(is);
|
||||
if(v != 1) {
|
||||
throw new IOException("Unknown EBP version: " + v);
|
||||
}
|
||||
v = is.read();
|
||||
if(v != 3) {
|
||||
throw new IOException("Invalid component count: " + v);
|
||||
int c = readByte(is);
|
||||
if(c != 3 && c != 4) {
|
||||
throw new IOException("Invalid component count: " + c);
|
||||
}
|
||||
int w = is.read() | (is.read() << 8);
|
||||
int h = is.read() | (is.read() << 8);
|
||||
int w = readByte(is) | (readByte(is) << 8);
|
||||
int h = readByte(is) | (readByte(is) << 8);
|
||||
ImageData img = new ImageData(w, h, true);
|
||||
alpha <<= 24;
|
||||
v = is.read();
|
||||
v = readByte(is);
|
||||
if(v == 0) {
|
||||
for(int i = 0, l = w * h; i < l; ++i) {
|
||||
img.pixels[i] = is.read() | (is.read() << 8) | (is.read() << 16) | alpha;
|
||||
if(c == 3) {
|
||||
for(int i = 0, l = w * h; i < l; ++i) {
|
||||
img.pixels[i] = readByte(is) | (readByte(is) << 8) | (readByte(is) << 16) | 0xFF000000;
|
||||
}
|
||||
}else {
|
||||
for(int i = 0, l = w * h; i < l; ++i) {
|
||||
img.pixels[i] = readByte(is) | (readByte(is) << 8) | (readByte(is) << 16) | (readByte(is) << 24);
|
||||
}
|
||||
}
|
||||
}else if(v == 1) {
|
||||
int paletteSize = is.read();
|
||||
int[] palette = new int[paletteSize + 1];
|
||||
palette[0] = alpha;
|
||||
for(int i = 0; i < paletteSize; ++i) {
|
||||
palette[i + 1] = is.read() | (is.read() << 8) | (is.read() << 16) | alpha;
|
||||
int paletteSize = readByte(is) + 1;
|
||||
int[] palette = new int[paletteSize];
|
||||
palette[0] = 0xFF000000;
|
||||
if(c == 3) {
|
||||
for(int i = 1; i < paletteSize; ++i) {
|
||||
palette[i] = readByte(is) | (readByte(is) << 8) | (readByte(is) << 16) | 0xFF000000;
|
||||
}
|
||||
}else {
|
||||
for(int i = 1; i < paletteSize; ++i) {
|
||||
palette[i] = readByte(is) | (readByte(is) << 8) | (readByte(is) << 16) | (readByte(is) << 24);
|
||||
}
|
||||
}
|
||||
int bpp = is.read();
|
||||
byte[] readSet = new byte[is.read() | (is.read() << 8) | (is.read() << 16)];
|
||||
is.read(readSet);
|
||||
int bpp = readByte(is);
|
||||
byte[] readSet = new byte[readByte(is) | (readByte(is) << 8) | (readByte(is) << 16)];
|
||||
IOUtils.readFully(is, readSet);
|
||||
for(int i = 0, l = w * h; i < l; ++i) {
|
||||
img.pixels[i] = palette[getFromBits(i * bpp, bpp, readSet)];
|
||||
}
|
||||
}else {
|
||||
throw new IOException("Unknown EBP storage type: " + v);
|
||||
}
|
||||
if(is.read() != ':' || is.read() != '>') {
|
||||
if(readByte(is) != ':' || readByte(is) != '>') {
|
||||
throw new IOException("Invalid footer! (:>)");
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
public static ImageData loadTextureSafe(InputStream is, int alpha) throws IOException {
|
||||
public static ImageData loadTextureSafe(InputStream is) throws IOException {
|
||||
ImageData bufferedimage;
|
||||
try {
|
||||
bufferedimage = loadTexture(is, alpha);
|
||||
bufferedimage = loadTexture(is);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
|
@ -52,11 +52,13 @@ public class PBRTextureMapUtils {
|
||||
if(res.getResourcePackName().equals(resourcePack)) {
|
||||
ImageData toRet = TextureUtil.readBufferedImage(res.getInputStream());
|
||||
if(ext.equals("_s")) {
|
||||
for(int i = 0, j; i < toRet.pixels.length; ++i) {
|
||||
// swap B and A, because labPBR support
|
||||
int a = (toRet.pixels[i] >>> 24) & 0xFF;
|
||||
for(int i = 0, j, a, b; i < toRet.pixels.length; ++i) {
|
||||
j = toRet.pixels[i];
|
||||
a = (j >>> 24) & 0xFF;
|
||||
if(a == 0xFF) a = 0;
|
||||
toRet.pixels[i] = (toRet.pixels[i] & 0x0000FFFF) | Math.min(a << 18, 0xFF0000) | 0xFF000000;
|
||||
b = (((j >>> 16) & 0xFF) - 65) * 255 / 190;
|
||||
if(b < 0) b = 0;
|
||||
toRet.pixels[i] = (j & 0x0000FFFF) | Math.min(a << 18, 0xFF0000) | ((255 - b) << 24);
|
||||
}
|
||||
}
|
||||
return toRet;
|
||||
@ -74,7 +76,7 @@ public class PBRTextureMapUtils {
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
try {
|
||||
return EaglerBitwisePackedTexture.loadTextureSafe(resMgr.getResource(new ResourceLocation("eagler:glsl/deferred/assets_pbr/" + fname + ".ebp")).getInputStream(), 255);
|
||||
return EaglerBitwisePackedTexture.loadTextureSafe(resMgr.getResource(new ResourceLocation("eagler:glsl/deferred/assets_pbr/" + fname + ".ebp")).getInputStream());
|
||||
}catch(Throwable t) {
|
||||
// dead code because teavm
|
||||
t.toString();
|
||||
|
@ -70,7 +70,7 @@ public class ClientV5MessageHandler extends ClientV4MessageHandler {
|
||||
}
|
||||
|
||||
public void handleServer(SPacketClientStateFlagV5EAG packet) {
|
||||
StateFlags.setFlag(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.state);
|
||||
StateFlags.setFlag(netHandler, new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.state);
|
||||
}
|
||||
|
||||
public void handleServer(SPacketDisplayWebViewURLV5EAG packet) {
|
||||
|
@ -17,6 +17,7 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.socket.protocol.client;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||
|
||||
public class StateFlags {
|
||||
|
||||
@ -29,18 +30,23 @@ public class StateFlags {
|
||||
public static final EaglercraftUUID DISABLE_SKIN_URL_LOOKUP = new EaglercraftUUID(0xC41D641BE2DA4094L,
|
||||
0xB1B2DFF2E9D08180L);
|
||||
|
||||
public static final EaglercraftUUID SET_MAX_MULTI_PACKET = new EaglercraftUUID(0x877BC5F5A2154DDBL,
|
||||
0xB493BE790A763E90L);
|
||||
|
||||
public static boolean eaglerPlayerFlag = false;
|
||||
|
||||
public static boolean eaglerPlayerFlagSupervisor = false;
|
||||
|
||||
public static boolean disableSkinURLLookup = false;
|
||||
|
||||
public static void setFlag(EaglercraftUUID flag, int value) {
|
||||
public static void setFlag(NetHandlerPlayClient handler, EaglercraftUUID flag, int value) {
|
||||
if (flag.equals(EAGLER_PLAYER_FLAG_PRESENT)) {
|
||||
eaglerPlayerFlag = (value & 1) != 0;
|
||||
eaglerPlayerFlagSupervisor = (value & 2) != 0;
|
||||
} else if (flag.equals(DISABLE_SKIN_URL_LOOKUP)) {
|
||||
disableSkinURLLookup = value != 0;
|
||||
} else if (flag.equals(SET_MAX_MULTI_PACKET)) {
|
||||
handler.getEaglerMessageController().setMaxMultiPacket(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,9 @@ public class InjectedMessageController extends MessageController {
|
||||
byteInputStreamSingleton.feedBuffer(data, offset);
|
||||
inputStreamSingleton.readByte();
|
||||
if(data[offset + 1] == (byte) 0xFF) {
|
||||
if(inputStreamSingleton.available() > 32768) {
|
||||
throw new IOException("Impossible large multi-packet received: " + inputStreamSingleton.available());
|
||||
}
|
||||
inputStreamSingleton.readByte();
|
||||
int count = inputStreamSingleton.readVarInt();
|
||||
for(int i = 0, j, k; i < count; ++i) {
|
||||
@ -134,7 +137,7 @@ public class InjectedMessageController extends MessageController {
|
||||
lastLen = GamePacketOutputBuffer.getVarIntSize(i) + i;
|
||||
totalLen += lastLen;
|
||||
++sendCount;
|
||||
}while(totalLen < 32760 && sendCount < total - start);
|
||||
}while(totalLen < 32760 && sendCount < total - start && sendCount < maxMultiPacket);
|
||||
if(totalLen >= 32760) {
|
||||
--sendCount;
|
||||
totalLen -= lastLen;
|
||||
|
@ -138,7 +138,7 @@ public class LegacyMessageController extends MessageController {
|
||||
lastLen = GamePacketOutputBuffer.getVarIntSize(i) + i;
|
||||
totalLen += lastLen;
|
||||
++sendCount;
|
||||
}while(totalLen < 32760 && sendCount < total - start);
|
||||
}while(totalLen < 32760 && sendCount < total - start && sendCount < maxMultiPacket);
|
||||
if(totalLen >= 32760) {
|
||||
--sendCount;
|
||||
totalLen -= lastLen;
|
||||
|
@ -37,6 +37,7 @@ public abstract class MessageController {
|
||||
protected final int sendDirection;
|
||||
protected final int receiveDirection;
|
||||
protected List<GameMessagePacket> sendQueue;
|
||||
protected int maxMultiPacket = 64;
|
||||
|
||||
public MessageController(GamePluginMessageProtocol protocol, GameMessageHandler handler, int direction) {
|
||||
this.protocol = protocol;
|
||||
@ -57,6 +58,10 @@ public abstract class MessageController {
|
||||
return sendQueue != null;
|
||||
}
|
||||
|
||||
public void setMaxMultiPacket(int max) {
|
||||
this.maxMultiPacket = max;
|
||||
}
|
||||
|
||||
public void sendPacket(GameMessagePacket packet) {
|
||||
if(sendQueue != null) {
|
||||
sendQueue.add(packet);
|
||||
|
@ -227,9 +227,11 @@ public class PacketBufferInputWrapper implements GamePacketInputBuffer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readByteArrayMC() throws IOException {
|
||||
public byte[] readByteArrayMC(int maxLen) throws IOException {
|
||||
try {
|
||||
return buffer.readByteArray();
|
||||
return buffer.readByteArray(maxLen);
|
||||
}catch(DecoderException ex) {
|
||||
throw new IOException(ex.getMessage());
|
||||
}catch(IndexOutOfBoundsException ex) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.export;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
@ -67,13 +68,13 @@ public class EPKDecompiler implements Closeable {
|
||||
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||
}
|
||||
|
||||
IOUtils.skipFully(is, is.read()); // skip filename
|
||||
IOUtils.skipFully(is, loadByte(is)); // skip filename
|
||||
IOUtils.skipFully(is, loadShort(is)); // skip comment
|
||||
IOUtils.skipFully(is, 8); // skip millis date
|
||||
|
||||
numFiles = loadInt(is);
|
||||
|
||||
char compressionType = (char)is.read();
|
||||
char compressionType = (char)loadByte(is);
|
||||
|
||||
switch(compressionType) {
|
||||
case 'G':
|
||||
@ -137,7 +138,7 @@ public class EPKDecompiler implements Closeable {
|
||||
throw new IOException("File '" + name + "' has an invalid checksum");
|
||||
}
|
||||
|
||||
if(zis.read() != ':') {
|
||||
if(loadByte(zis) != ':') {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
}else {
|
||||
@ -145,7 +146,7 @@ public class EPKDecompiler implements Closeable {
|
||||
IOUtils.readFully(zis, data);
|
||||
}
|
||||
|
||||
if(zis.read() != '>') {
|
||||
if(loadByte(zis) != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
@ -155,15 +156,23 @@ public class EPKDecompiler implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
public static final int loadShort(InputStream is) throws IOException {
|
||||
return (is.read() << 8) | is.read();
|
||||
public static int loadByte(InputStream is) throws IOException {
|
||||
int i = is.read();
|
||||
if (i < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public static final int loadInt(InputStream is) throws IOException {
|
||||
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||
public static int loadShort(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
public static final String readASCII(byte[] bytesIn) throws IOException {
|
||||
public static int loadInt(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 24) | (loadByte(is) << 16) | (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
public static String readASCII(byte[] bytesIn) throws IOException {
|
||||
char[] charIn = new char[bytesIn.length];
|
||||
for(int i = 0; i < bytesIn.length; ++i) {
|
||||
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||
@ -171,11 +180,11 @@ public class EPKDecompiler implements Closeable {
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
public static final String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = bytesIn.read();
|
||||
public static String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = loadByte(bytesIn);
|
||||
char[] charIn = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||
charIn[i] = (char)loadByte(bytesIn);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public interface GamePacketInputBuffer extends DataInput {
|
||||
|
||||
String readStringEaglerASCII16() throws IOException;
|
||||
|
||||
byte[] readByteArrayMC() throws IOException;
|
||||
byte[] readByteArrayMC(int maxLen) throws IOException;
|
||||
|
||||
int available() throws IOException;
|
||||
|
||||
|
@ -53,7 +53,7 @@ public class CPacketWebViewMessageV4EAG implements GameMessagePacket {
|
||||
@Override
|
||||
public void readPacket(GamePacketInputBuffer buffer) throws IOException {
|
||||
type = buffer.readUnsignedByte();
|
||||
data = buffer.readByteArrayMC();
|
||||
data = buffer.readByteArrayMC(32750);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,7 +53,7 @@ public class SPacketWebViewMessageV4EAG implements GameMessagePacket {
|
||||
@Override
|
||||
public void readPacket(GamePacketInputBuffer buffer) throws IOException {
|
||||
type = buffer.readUnsignedByte();
|
||||
data = buffer.readByteArrayMC();
|
||||
data = buffer.readByteArrayMC(32750);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -171,8 +171,12 @@ public class SimpleInputBufferImpl extends DataInputStream implements GamePacket
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readByteArrayMC() throws IOException {
|
||||
byte[] abyte = new byte[this.readVarInt()];
|
||||
public byte[] readByteArrayMC(int maxLen) throws IOException {
|
||||
int i = this.readVarInt();
|
||||
if (i > maxLen) {
|
||||
throw new IOException("Byte array is too long: " + i + " > " + maxLen);
|
||||
}
|
||||
byte[] abyte = new byte[i];
|
||||
this.readFully(abyte);
|
||||
return abyte;
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
u51
|
||||
u52
|
@ -64,5 +64,8 @@
|
||||
"eaglerNoDelay": false,
|
||||
"ramdiskMode": false,
|
||||
"singleThreadMode": false,
|
||||
"enableEPKVersionCheck": true
|
||||
"enableEPKVersionCheck": true,
|
||||
"enforceVSync": true,
|
||||
"keepAliveHack": true,
|
||||
"finishOnSwap": true
|
||||
}
|
@ -64,5 +64,8 @@
|
||||
"eaglerNoDelay": false,
|
||||
"ramdiskMode": false,
|
||||
"singleThreadMode": false,
|
||||
"enableEPKVersionCheck": true
|
||||
"enableEPKVersionCheck": true,
|
||||
"enforceVSync": true,
|
||||
"keepAliveHack": true,
|
||||
"finishOnSwap": true
|
||||
}
|
@ -64,5 +64,8 @@
|
||||
"eaglerNoDelay": false,
|
||||
"ramdiskMode": false,
|
||||
"singleThreadMode": false,
|
||||
"enableEPKVersionCheck": true
|
||||
"enableEPKVersionCheck": true,
|
||||
"enforceVSync": true,
|
||||
"keepAliveHack": true,
|
||||
"finishOnSwap": true
|
||||
}
|
@ -83,7 +83,6 @@ uniform sampler2D u_metalsLUT;
|
||||
#define LIB_INCLUDE_PBR_LIGHTING_FUNCTION
|
||||
#define LIB_INCLUDE_PBR_LIGHTING_PREFETCH
|
||||
#EAGLER INCLUDE (3) "eagler:glsl/deferred/lib/pbr_lighting.glsl"
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
uniform sampler2D u_irradianceMap;
|
||||
|
||||
@ -147,7 +146,7 @@ void main() {
|
||||
for(;;) {
|
||||
shadowTexPos4f = u_sunShadowMatrixLOD04f * shadowWorldPos4f;
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z + 0.0001), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z + 0.0001));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -156,7 +155,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 1.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -166,7 +165,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 2.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -176,7 +175,7 @@ void main() {
|
||||
#ifdef DO_COMPILE_SUN_SHADOWS
|
||||
lightColor3f *= shadowSample * skyLight;
|
||||
#endif
|
||||
vec3 normalWrap3f = normalVector3f * COMPARE_LT_C_C(dot(-worldDirection4f.xyz, normalVector3f), 0.0, -1.0, 1.0);
|
||||
vec3 normalWrap3f = normalVector3f * (dot(-worldDirection4f.xyz, normalVector3f) < 0.0 ? -1.0 : 1.0);
|
||||
lightColor3f = eaglercraftLighting(diffuseColor4f.rgb, lightColor3f, -worldDirection4f.xyz, u_sunDirection4f.xyz, normalWrap3f, materialData3f, metalN, metalK) * u_blockSkySunDynamicLightFac4f.z;
|
||||
}
|
||||
|
||||
@ -195,8 +194,8 @@ void main() {
|
||||
vec4 sample2 = textureLod(u_irradianceMap, irradianceMapSamplePos2f.xz * vec2(0.5, -0.25) + vec2(0.5, 0.75), 0.0);
|
||||
skyLight += mix(sample1.rgb, sample2.rgb, smoothstep(0.0, 1.0, irradianceMapSamplePos2f.y * -12.5 + 0.5)).rgb;
|
||||
}else {
|
||||
irradianceMapSamplePos2f.xz *= vec2(0.5, COMPARE_GT_C_C(irradianceMapSamplePos2f.y, 0.0, 0.25, -0.25));
|
||||
irradianceMapSamplePos2f.xz += vec2(0.5, COMPARE_GT_C_C(irradianceMapSamplePos2f.y, 0.0, 0.25, 0.75));
|
||||
irradianceMapSamplePos2f.xz *= vec2(0.5, irradianceMapSamplePos2f.y > 0.0 ? 0.25 : -0.25);
|
||||
irradianceMapSamplePos2f.xz += vec2(0.5, irradianceMapSamplePos2f.y > 0.0 ? 0.25 : 0.75);
|
||||
skyLight += textureLod(u_irradianceMap, irradianceMapSamplePos2f.xz, 0.0).rgb;
|
||||
}
|
||||
skyLight *= lightmapCoords2f.g * u_sunColor3f_sky1f.w;
|
||||
@ -211,7 +210,7 @@ void main() {
|
||||
for(int i = 0; i < safeLightCount; ++i) {
|
||||
dlightDist3f = worldPosition4f.xyz - u_dynamicLightArray[i].u_lightPosition4f.xyz;
|
||||
dlightDir3f = normalize(dlightDist3f);
|
||||
dlightDir3f = dlightDir3f * COMPARE_LT_C_C(dot(dlightDir3f, normalVector3f), 0.0, 1.0, -1.0);
|
||||
dlightDir3f = dlightDir3f * (dot(dlightDir3f, normalVector3f) < 0.0 ? 1.0 : -1.0);
|
||||
dlightDir3f = materialData3f.b == 1.0 ? normalVector3f : -dlightDir3f;
|
||||
if(dot(dlightDir3f, normalVector3f) <= 0.0) {
|
||||
continue;
|
||||
|
Binary file not shown.
@ -1,3 +1,5 @@
|
||||
#line 2
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
@ -14,22 +16,28 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// Assuming modern GPUs probably implement clamp, max, and ciel without branches
|
||||
// Tests for a D3D bug in ANGLE, this only became an issue recently...
|
||||
|
||||
// value1 > value2 ? 1.0 : 0.0
|
||||
#define COMPARE_GT_0_1(value1, value2) clamp(ceil(value1 - value2), 0.0, 1.0)
|
||||
precision highp float;
|
||||
precision highp sampler2DShadow;
|
||||
|
||||
// value1 > value2 ? N : 0.0
|
||||
#define COMPARE_GT_0_ANY(value1, value2) max(ceil(value1 - value2), 0.0)
|
||||
uniform sampler2DShadow u_testSampler;
|
||||
|
||||
// value1 < value2 ? 1.0 : 0.0
|
||||
#define COMPARE_LT_0_1(value1, value2) clamp(ceil(value2 - value1), 0.0, 1.0)
|
||||
out vec4 fragOut4f;
|
||||
|
||||
// value1 < value2 ? N : 0.0
|
||||
#define COMPARE_LT_0_ANY(value1, value2) max(ceil(value2 - value1), 0.0)
|
||||
|
||||
// value1 > value2 ? ifGT : ifLT
|
||||
#define COMPARE_GT_C_C(value1, value2, ifGT, ifLT) (COMPARE_GT_0_1(value1, value2) * (ifGT - ifLT) + ifLT)
|
||||
|
||||
// value1 < value2 ? ifLT : ifGT
|
||||
#define COMPARE_LT_C_C(value1, value2, ifLT, ifGT) (COMPARE_LT_0_1(value1, value2) * (ifLT - ifGT) + ifGT)
|
||||
void main() {
|
||||
float stupid = texture(u_testSampler, vec3(69.0, 69.0, 0.5));
|
||||
for(;;) {
|
||||
if (stupid != 69.0) {
|
||||
stupid = textureLod(u_testSampler, vec3(420.0, 420.0, 0.69), 0.0);
|
||||
break;
|
||||
}
|
||||
if (stupid != 420.0) {
|
||||
stupid = textureLod(u_testSampler, vec3(69.0, 69.0, 0.420), 0.0);
|
||||
break;
|
||||
}
|
||||
fragOut4f = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
fragOut4f = vec4(stupid);
|
||||
}
|
@ -73,15 +73,20 @@ void main() {
|
||||
vec3 sunDirection = u_sunDirection3f * vec3(1.0, 2.0, 1.0) * 0.025;
|
||||
float sunVisibility = sample0;
|
||||
|
||||
GET_CLOUDS((samplePos + sunDirection), sample1)
|
||||
vec3 pos = samplePos + sunDirection;
|
||||
GET_CLOUDS(pos, sample1)
|
||||
sunVisibility += sample1;
|
||||
GET_CLOUDS((samplePos + sunDirection * 2.0), sample1)
|
||||
pos = samplePos + sunDirection * 2.0;
|
||||
GET_CLOUDS(pos, sample1)
|
||||
sunVisibility += sample1;
|
||||
GET_CLOUDS((samplePos + sunDirection * 3.0), sample1)
|
||||
pos = samplePos + sunDirection * 3.0;
|
||||
GET_CLOUDS(pos, sample1)
|
||||
sunVisibility += sample1;
|
||||
GET_CLOUDS((samplePos + sunDirection * 4.0), sample1)
|
||||
pos = samplePos + sunDirection * 4.0;
|
||||
GET_CLOUDS(pos, sample1)
|
||||
sunVisibility += sample1;
|
||||
GET_CLOUDS((samplePos + sunDirection * 5.0), sample1)
|
||||
pos = samplePos + sunDirection * 5.0;
|
||||
GET_CLOUDS(pos, sample1)
|
||||
sunVisibility += sample1;
|
||||
|
||||
sunVisibility = exp2(-sunVisibility * 50.0);
|
||||
|
@ -60,7 +60,6 @@ uniform float u_skyLightFactor1f;
|
||||
#endif
|
||||
|
||||
#EAGLER INCLUDE (3) "eagler:glsl/deferred/lib/pbr_env_map.glsl"
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
void main() {
|
||||
vec3 diffuseColor3f;
|
||||
@ -87,7 +86,7 @@ void main() {
|
||||
|
||||
#ifdef COMPILE_GLOBAL_AMBIENT_OCCLUSION
|
||||
vec4 ao = textureLod(u_ssaoTexture, min(v_position2f * u_halfResolutionPixelAlignment2f, 1.0), 0.0);
|
||||
ao.g = mix(COMPARE_GT_0_1(0.0, ao.b), 1.0, ao.g);
|
||||
ao.g = ao.b > 0.0 ? ao.g : 1.0;
|
||||
shadow = mix(shadow, shadow * ao.g, 0.9);
|
||||
#endif
|
||||
|
||||
@ -103,8 +102,8 @@ void main() {
|
||||
vec4 sample2 = textureLod(u_irradianceMap, irradianceMapSamplePos2f.xz * vec2(0.5, -0.25) + vec2(0.5, 0.75), 0.0);
|
||||
skyLight += mix(sample1.rgb, sample2.rgb, smoothstep(0.0, 1.0, irradianceMapSamplePos2f.y * -12.5 + 0.5)).rgb;
|
||||
}else {
|
||||
irradianceMapSamplePos2f.xz *= vec2(0.5, COMPARE_GT_C_C(irradianceMapSamplePos2f.y, 0.0, 0.25, -0.25));
|
||||
irradianceMapSamplePos2f.xz += vec2(0.5, COMPARE_GT_C_C(irradianceMapSamplePos2f.y, 0.0, 0.25, 0.75));
|
||||
irradianceMapSamplePos2f.xz *= vec2(0.5, irradianceMapSamplePos2f.y > 0.0 ? 0.25 : -0.25);
|
||||
irradianceMapSamplePos2f.xz += vec2(0.5, irradianceMapSamplePos2f.y > 0.0 ? 0.25 : 0.75);
|
||||
skyLight += textureLod(u_irradianceMap, irradianceMapSamplePos2f.xz, 0.0).rgb;
|
||||
}
|
||||
|
||||
@ -115,8 +114,8 @@ void main() {
|
||||
vec3 specular = vec3(0.0);
|
||||
|
||||
#ifdef COMPILE_ENV_MAP_REFLECTIONS
|
||||
float f = COMPARE_LT_0_ANY(materialData4f.g, 0.06);
|
||||
f += COMPARE_LT_0_ANY(materialData4f.r, 0.5);
|
||||
float f = materialData4f.g < 0.06 ? 1.0 : 0.0;
|
||||
f += materialData4f.r < 0.5 ? 1.0 : 0.0;
|
||||
while((materialData4f.a >= 0.5 ? f : -1.0) == 0.0) {
|
||||
vec4 worldPosition4f = vec4(v_position2f, depth, 1.0) * 2.0 - 1.0;
|
||||
worldPosition4f = u_inverseProjMatrix4f * worldPosition4f;
|
||||
@ -138,8 +137,8 @@ void main() {
|
||||
vec4 sample2 = textureLod(u_environmentMap, reflectDir.xz * vec2(0.5, -0.25) + vec2(0.5, 0.75), 0.0);
|
||||
envMapSample4f = vec4(mix(sample1.rgb, sample2.rgb, smoothstep(0.0, 1.0, reflectDir.y * -12.5 + 0.5)).rgb, min(sample1.a, sample2.a));
|
||||
}else {
|
||||
reflectDir.xz = reflectDir.xz * vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0, 0.25, -0.25));
|
||||
reflectDir.xz += vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0, 0.25, 0.75));
|
||||
reflectDir.xz = reflectDir.xz * vec2(0.5, reflectDir.y > 0.0 ? 0.25 : -0.25);
|
||||
reflectDir.xz += vec2(0.5, reflectDir.y > 0.0 ? 0.25 : 0.75);
|
||||
envMapSample4f = textureLod(u_environmentMap, reflectDir.xz, 0.0);
|
||||
}
|
||||
envMapSample4f.a += min(lightmapCoords2f.g * 2.0, 1.0) * (1.0 - envMapSample4f.a);
|
||||
@ -153,8 +152,8 @@ void main() {
|
||||
|
||||
#ifdef COMPILE_SCREEN_SPACE_REFLECTIONS
|
||||
#ifndef COMPILE_ENV_MAP_REFLECTIONS
|
||||
float f = COMPARE_LT_0_ANY(materialData4f.g, 0.06);
|
||||
f += COMPARE_LT_0_ANY(materialData4f.r, 0.5);
|
||||
float f = materialData4f.g < 0.06 ? 1.0 : 0.0;
|
||||
f += materialData4f.r < 0.5 ? 1.0 : 0.0;
|
||||
if(f == 0.0) {
|
||||
#else
|
||||
if((materialData4f.a < 0.5 ? f : -1.0) == 0.0) {
|
||||
|
@ -162,7 +162,6 @@ uniform sampler2D u_lightShaftsTexture;
|
||||
#endif
|
||||
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/pbr_env_map.glsl"
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
#ifdef DO_COMPILE_SUN_SHADOWS
|
||||
uniform sampler2DShadow u_sunShadowDepthTexture;
|
||||
@ -179,7 +178,7 @@ vec2(0.675, 0.682));
|
||||
tmpVec2 = clamp(tmpVec2, vec2(0.001), vec2(0.999));\
|
||||
tmpVec2.y += lod;\
|
||||
tmpVec2.y *= SUN_SHADOW_MAP_FRAC;\
|
||||
accum += textureLod(tex, vec3(tmpVec2, vec3Pos.z + 0.0001), 0.0);
|
||||
accum += CMPLOD0_D3D_WORKAROUND(tex, vec3(tmpVec2, vec3Pos.z + 0.0001));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -308,7 +307,7 @@ void main() {
|
||||
for(;;) {
|
||||
shadowTexPos4f = u_sunShadowMatrixLOD04f * shadowWorldPos4f;
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z));
|
||||
#ifdef COMPILE_SUN_SHADOW_SMOOTH
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(0, u_sunShadowDepthTexture, 0.0, shadowTexPos4f.xyz, shadowSample, tmpVec2)
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(1, u_sunShadowDepthTexture, 0.0, shadowTexPos4f.xyz, shadowSample, tmpVec2)
|
||||
@ -327,7 +326,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 1.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -337,7 +336,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 2.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -355,8 +354,8 @@ void main() {
|
||||
|
||||
// =========== ENVIRONMENT MAP =========== //
|
||||
|
||||
f = COMPARE_LT_0_ANY(materialData4f.g, 0.06);
|
||||
f += COMPARE_LT_0_ANY(materialData4f.r, 0.5);
|
||||
f = materialData4f.g < 0.06 ? 1.0 : 0.0;
|
||||
f += materialData4f.r < 0.5 ? 1.0 : 0.0;
|
||||
while(f == 0.0) {
|
||||
float dst2 = dot(worldPosition4f.xyz, worldPosition4f.xyz);
|
||||
if(dst2 > 25.0) {
|
||||
@ -373,8 +372,8 @@ void main() {
|
||||
vec4 sample2 = textureLod(u_environmentMap, reflectDir.xz * vec2(0.5, -0.25) + vec2(0.5, 0.75), 0.0);
|
||||
envMapSample4f = vec4(mix(sample1.rgb, sample2.rgb, smoothstep(0.0, 1.0, reflectDir.y * -12.5 + 0.5)).rgb, min(sample1.a, sample2.a));
|
||||
}else {
|
||||
reflectDir.xz = reflectDir.xz * vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0, 0.25, -0.25));
|
||||
reflectDir.xz += vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0, 0.25, 0.75));
|
||||
reflectDir.xz = reflectDir.xz * vec2(0.5, reflectDir.y > 0.0 ? 0.25 : -0.25);
|
||||
reflectDir.xz += vec2(0.5, reflectDir.y > 0.0 ? 0.25 : 0.75);
|
||||
envMapSample4f = textureLod(u_environmentMap, reflectDir.xz, 0.0);
|
||||
}
|
||||
envMapSample4f.a += min(lightmapCoords2f.g * 2.0, 1.0) * (1.0 - envMapSample4f.a);
|
||||
@ -401,8 +400,8 @@ void main() {
|
||||
vec4 sample2 = textureLod(u_irradianceMap, irradianceMapSamplePos2f.xz * vec2(0.5, -0.25) + vec2(0.5, 0.75), 0.0);
|
||||
skyLight += mix(sample1.rgb, sample2.rgb, smoothstep(0.0, 1.0, irradianceMapSamplePos2f.y * -12.5 + 0.5)).rgb;
|
||||
}else {
|
||||
irradianceMapSamplePos2f.xz *= vec2(0.5, COMPARE_GT_C_C(irradianceMapSamplePos2f.y, 0.0, 0.25, -0.25));
|
||||
irradianceMapSamplePos2f.xz += vec2(0.5, COMPARE_GT_C_C(irradianceMapSamplePos2f.y, 0.0, 0.25, 0.75));
|
||||
irradianceMapSamplePos2f.xz *= vec2(0.5, irradianceMapSamplePos2f.y > 0.0 ? 0.25 : -0.25);
|
||||
irradianceMapSamplePos2f.xz += vec2(0.5, irradianceMapSamplePos2f.y > 0.0 ? 0.25 : 0.75);
|
||||
skyLight += textureLod(u_irradianceMap, irradianceMapSamplePos2f.xz, 0.0).rgb;
|
||||
}
|
||||
skyLight *= lightmapCoords2f.g * u_sunColor3f_sky1f.w;
|
||||
@ -437,7 +436,7 @@ void main() {
|
||||
vec4 fogBlend4f = vec4(0.0);
|
||||
#ifndef COMPILE_ENABLE_TEX_GEN
|
||||
while(u_fogParameters4f.x > 0.0) {
|
||||
float atmos = COMPARE_LT_C_C(u_fogParameters4f.x, 4.0, 0.0, 4.0);
|
||||
float atmos = u_fogParameters4f.x >= 4.0 ? 4.0 : 0.0;
|
||||
float type = u_fogParameters4f.x - atmos;
|
||||
fogBlend4f = mix(u_fogColorLight4f, u_fogColorDark4f, lightmapCoords2f.g);
|
||||
|
||||
|
@ -85,8 +85,6 @@ layout(std140) uniform u_worldLightingData {
|
||||
uniform sampler2D u_environmentMap;
|
||||
uniform sampler2D u_brdfLUT;
|
||||
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
#define GLASS_ROUGHNESS 0.15
|
||||
#define GLASS_F0 0.4
|
||||
|
||||
@ -135,7 +133,7 @@ vec2(0.675, 0.682));
|
||||
tmpVec2 = clamp(tmpVec2, vec2(0.001), vec2(0.999));\
|
||||
tmpVec2.y += lod;\
|
||||
tmpVec2.y *= SUN_SHADOW_MAP_FRAC;\
|
||||
accum += textureLod(tex, vec3(tmpVec2, vec3Pos.z + 0.0001), 0.0);
|
||||
accum += CMPLOD0_D3D_WORKAROUND(tex, vec3(tmpVec2, vec3Pos.z + 0.0001));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -193,7 +191,7 @@ void main() {
|
||||
for(;;) {
|
||||
shadowTexPos4f = u_sunShadowMatrixLOD04f * shadowWorldPos4f;
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z + 0.0001), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z + 0.0001));
|
||||
#ifdef COMPILE_SUN_SHADOW_SMOOTH
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(0, u_sunShadowDepthTexture, 0.0, shadowTexPos4f.xyz, shadowSample, tmpVec2)
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(1, u_sunShadowDepthTexture, 0.0, shadowTexPos4f.xyz, shadowSample, tmpVec2)
|
||||
@ -212,7 +210,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 1.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -222,7 +220,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 2.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -253,8 +251,8 @@ void main() {
|
||||
vec4 sample2 = textureLod(u_environmentMap, reflectDir.xz * vec2(0.5, -0.25) + vec2(0.5, 0.75), 0.0);
|
||||
envMapSample4f = vec4(mix(sample1.rgb, sample2.rgb, smoothstep(0.0, 1.0, reflectDir.y * -12.5 + 0.5)).rgb, min(sample1.a, sample2.a));
|
||||
}else {
|
||||
reflectDir.xz = reflectDir.xz * vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0, 0.25, -0.25));
|
||||
reflectDir.xz += vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0 , 0.25, 0.75));
|
||||
reflectDir.xz = reflectDir.xz * vec2(0.5, reflectDir.y > 0.0 ? 0.25 : -0.25);
|
||||
reflectDir.xz += vec2(0.5, reflectDir.y > 0.0 ? 0.25 : 0.75);
|
||||
envMapSample4f = textureLod(u_environmentMap, reflectDir.xz, 0.0);
|
||||
}
|
||||
envMapSample4f.a += min(lightmapCoords2f.g * 2.0, 1.0) * (1.0 - envMapSample4f.a);
|
||||
@ -292,7 +290,7 @@ void main() {
|
||||
|
||||
float fogFade = 0.0;
|
||||
if(u_fogParameters4f.x > 0.0) {
|
||||
float atmos = COMPARE_LT_C_C(u_fogParameters4f.x, 4.0, 0.0, 4.0);
|
||||
float atmos = u_fogParameters4f.x >= 4.0 ? 4.0 : 0.0;
|
||||
float type = u_fogParameters4f.x - atmos;
|
||||
fogFade = mix(u_fogColorDark4f.a, u_fogColorLight4f.a, lightmapCoords2f.g);
|
||||
|
||||
|
@ -108,7 +108,7 @@ vec2(0.675, 0.682));
|
||||
tmpVec2 = clamp(tmpVec2, vec2(0.001), vec2(0.999));\
|
||||
tmpVec2.y += lod;\
|
||||
tmpVec2.y *= SUN_SHADOW_MAP_FRAC;\
|
||||
accum += textureLod(tex, vec3(tmpVec2, vec3Pos.z + 0.0001), 0.0);
|
||||
accum += CMPLOD0_D3D_WORKAROUND(tex, vec3(tmpVec2, vec3Pos.z + 0.0001));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -122,8 +122,6 @@ uniform sampler2D u_normalMap;
|
||||
uniform vec4 u_waterWindOffset4f;
|
||||
uniform vec3 u_wavingBlockOffset3f;
|
||||
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
#define WATER_ROUGHNESS 0.05
|
||||
#define WATER_F0 0.5
|
||||
|
||||
@ -305,7 +303,7 @@ void main() {
|
||||
for(;;) {
|
||||
shadowTexPos4f = u_sunShadowMatrixLOD04f * shadowWorldPos4f;
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z + 0.0001), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowTexPos4f.z + 0.0001));
|
||||
#ifdef COMPILE_SUN_SHADOW_SMOOTH
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(0, u_sunShadowDepthTexture, 0.0, shadowTexPos4f.xyz, shadowSample, tmpVec2)
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(1, u_sunShadowDepthTexture, 0.0, shadowTexPos4f.xyz, shadowSample, tmpVec2)
|
||||
@ -324,7 +322,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 1.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -334,7 +332,7 @@ void main() {
|
||||
if(shadowTexPos4f.xyz == clamp(shadowTexPos4f.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowTexPos4f.y += 2.0;
|
||||
shadowTexPos4f.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowTexPos4f.xy, shadowTexPos4f.z + 0.00015));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -352,8 +350,8 @@ void main() {
|
||||
lightmapCoords2f *= lightmapCoords2f;
|
||||
|
||||
float e = 0.0;
|
||||
e += COMPARE_GT_0_ANY(envMapSample4f.g, 0.0);
|
||||
e += COMPARE_LT_0_ANY(lightmapCoords2f.y, 0.5);
|
||||
e += envMapSample4f.g <= 0.0 ? 0.0 : 1.0;
|
||||
e += lightmapCoords2f.y > 0.5 ? 0.0 : 1.0;
|
||||
//e += abs(normalVector3f.y) > 0.1 ? 0.0 : 1.0;
|
||||
if(e == 0.0) {
|
||||
vec3 reflectDir = reflect(worldDirection4f.xyz, normalVector3f);
|
||||
@ -366,8 +364,8 @@ void main() {
|
||||
vec4 sample2 = textureLod(u_environmentMap, reflectDir.xz * vec2(0.5, -0.25) + vec2(0.5, 0.75), 0.0);
|
||||
envMapSample4f = vec4(mix(sample1.rgb, sample2.rgb, smoothstep(0.0, 1.0, reflectDir.y * -12.5 + 0.5)).rgb, min(sample1.a, sample2.a));
|
||||
}else {
|
||||
reflectDir.xz *= vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0, 0.25, -0.25));
|
||||
reflectDir.xz += vec2(0.5, COMPARE_GT_C_C(reflectDir.y, 0.0, 0.25, 0.75));
|
||||
reflectDir.xz *= vec2(0.5, reflectDir.y > 0.0 ? 0.25 : -0.25);
|
||||
reflectDir.xz += vec2(0.5, reflectDir.y > 0.0 ? 0.25 : 0.75);
|
||||
envMapSample4f = textureLod(u_environmentMap, reflectDir.xz, 0.0);
|
||||
}
|
||||
envMapSample4f.rgb *= (lightmapCoords2f.y * 2.0 - 1.0);
|
||||
|
@ -84,8 +84,6 @@ uniform vec4 u_nearFarPlane4f;
|
||||
|
||||
uniform vec4 u_pixelAlignment4f;
|
||||
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
#define reprojDepthLimit 0.25
|
||||
|
||||
#define GET_LINEAR_DEPTH_FROM_VALUE(depthSample) (u_nearFarPlane4f.z / (u_nearFarPlane4f.y + u_nearFarPlane4f.x + (depthSample * 2.0 - 1.0) * u_nearFarPlane4f.w))
|
||||
@ -137,9 +135,9 @@ void main() {
|
||||
|
||||
#ifdef COMPILE_REPROJECT_SSR
|
||||
vec4 materials = textureLod(u_gbufferMaterialTexture, v_position2f2, 0.0);
|
||||
float f = COMPARE_LT_0_ANY(materials.g, 0.06);
|
||||
f += COMPARE_LT_0_ANY(materials.r, 0.5);
|
||||
f += COMPARE_GT_0_ANY(materials.a, 0.5);
|
||||
float f = materials.g < 0.06 ? 1.0 : 0.0;
|
||||
f += materials.r < 0.5 ? 1.0 : 0.0;
|
||||
f += materials.a > 0.5 ? 1.0 : 0.0;
|
||||
if(f > 0.0) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "§eHigh Performance PBR",
|
||||
"desc": "Pack made from scratch specifically for this client, designed to give what I call the best balance between quality and performance possible in a browser but obviously that's just my opinion",
|
||||
"vers": "1.4.1",
|
||||
"vers": "1.4.2",
|
||||
"author": "lax1dude",
|
||||
"api_vers": 1,
|
||||
"features": [
|
||||
|
@ -67,7 +67,7 @@ vec2(0.675, 0.682));
|
||||
tmpVec2 = clamp(tmpVec2, vec2(0.001), vec2(0.999));\
|
||||
tmpVec2.y += lod;\
|
||||
tmpVec2.y *= SUN_SHADOW_MAP_FRAC;\
|
||||
accum += textureLod(tex, vec3(tmpVec2, vec3Pos.z + 0.0001), 0.0);
|
||||
accum += CMPLOD0_D3D_WORKAROUND(tex, vec3(tmpVec2, vec3Pos.z + 0.0001));
|
||||
#endif
|
||||
|
||||
uniform vec3 u_sunDirection3f;
|
||||
@ -106,7 +106,7 @@ void main() {
|
||||
for(;;) {
|
||||
shadowSpacePosition = u_sunShadowMatrixLOD04f * worldSpacePosition;
|
||||
if(shadowSpacePosition.xyz == clamp(shadowSpacePosition.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowSpacePosition.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowSpacePosition.z + 0.0001), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowSpacePosition.xy * vec2(1.0, SUN_SHADOW_MAP_FRAC), shadowSpacePosition.z + 0.0001));
|
||||
#ifdef COMPILE_SUN_SHADOW_SMOOTH
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(0, u_sunShadowDepthTexture, 0.0, shadowSpacePosition.xyz, shadowSample, tmpVec2)
|
||||
SMOOTH_SHADOW_POISSON_SAMPLE(1, u_sunShadowDepthTexture, 0.0, shadowSpacePosition.xyz, shadowSample, tmpVec2)
|
||||
@ -128,7 +128,7 @@ void main() {
|
||||
if(shadowSpacePosition.xyz == clamp(shadowSpacePosition.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowSpacePosition.y += 1.0;
|
||||
shadowSpacePosition.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowSpacePosition.xy, shadowSpacePosition.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowSpacePosition.xy, shadowSpacePosition.z + 0.00015));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -138,7 +138,7 @@ void main() {
|
||||
if(shadowSpacePosition.xyz == clamp(shadowSpacePosition.xyz, vec3(0.005), vec3(0.995))) {
|
||||
shadowSpacePosition.y += 2.0;
|
||||
shadowSpacePosition.y *= SUN_SHADOW_MAP_FRAC;
|
||||
shadowSample = textureLod(u_sunShadowDepthTexture, vec3(shadowSpacePosition.xy, shadowSpacePosition.z + 0.00015), 0.0);
|
||||
shadowSample = CMPLOD0_D3D_WORKAROUND(u_sunShadowDepthTexture, vec3(shadowSpacePosition.xy, shadowSpacePosition.z + 0.00015));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -44,8 +44,6 @@ uniform sampler2D u_gbufferDepthTexture;
|
||||
|
||||
#define SKY_BRIGHTNESS 5.0
|
||||
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
void main() {
|
||||
gl_FragDepth = 0.0;
|
||||
vec3 viewDir = normalize(v_position3f);
|
||||
@ -55,7 +53,7 @@ void main() {
|
||||
float f = max(dot(viewDir, u_sunDirection3f) - 0.995, 0.0) * 100.0;
|
||||
float intensity = min(f * 2.0, 1.0);
|
||||
intensity *= intensity * intensity * intensity * textureLod(u_sunOcclusion, vec2(0.5, 0.5), 0.0).r * 2.0;
|
||||
intensity *= 1.0 - COMPARE_GT_0_1(textureLod(u_gbufferDepthTexture, (v_positionClip3f.xy / v_positionClip3f.z) * 0.5 + 0.5, 0.0).r, 0.0);
|
||||
intensity *= step(textureLod(u_gbufferDepthTexture, (v_positionClip3f.xy / v_positionClip3f.z) * 0.5 + 0.5, 0.0).r, 0.0);
|
||||
output4f = vec4(v_color3f * SKY_BRIGHTNESS + intensity * u_sunColor3f, 0.0);
|
||||
#endif
|
||||
#ifdef COMPILE_CLOUDS
|
||||
|
@ -33,8 +33,6 @@ uniform mat4 u_inverseProjectionMatrix4f;
|
||||
|
||||
uniform mat2 u_randomizerDataMatrix2f;
|
||||
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
const vec3 ssaoKernel[8] = vec3[](
|
||||
vec3(0.599,0.721,0.350),vec3(0.114,0.791,0.601),
|
||||
vec3(0.067,0.995,0.069),vec3(0.511,-0.510,0.692),
|
||||
@ -50,8 +48,8 @@ vec3(0.716,-0.439,0.543),vec3(-0.400,0.733,0.550));
|
||||
tmpVec4_2.zw = matProjInv2f * vec4(tmpVec4_2.xy, textureLod(u_gbufferDepthTexture, tmpVec4_2.xy * 0.5 + 0.5, 0.0).r * 2.0 - 1.0, 1.0);\
|
||||
tmpVec4_2.z /= tmpVec4_2.w;\
|
||||
tmpVec4_2.x = smoothstep(0.0, 1.0, radius * 0.5 / abs(pos.z - tmpVec4_2.z));\
|
||||
divisor += COMPARE_GT_0_1(tmpVec4_2.x, 0.0);\
|
||||
occlusion += COMPARE_GT_0_1(tmpVec4_2.z, tmpVec4_1.z) * tmpVec4_2.x;
|
||||
divisor += tmpVec4_2.x > 0.0 ? 1.0 : 0.0;\
|
||||
occlusion += (tmpVec4_2.z >= tmpVec4_1.z ? 1.0 : 0.0) * tmpVec4_2.x;
|
||||
|
||||
void main() {
|
||||
vec3 originalClipSpacePos = vec3(v_position2f, textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r);
|
||||
|
@ -48,8 +48,6 @@ uniform mat4 u_sunShadowMatrixLOD24f;
|
||||
#define SUN_SHADOW_MAP_FRAC 0.3333333
|
||||
#endif
|
||||
|
||||
#EAGLER INCLUDE (4) "eagler:glsl/deferred/lib/branchless_comparison.glsl"
|
||||
|
||||
const vec2 POISSON_DISK[4] = vec2[](
|
||||
vec2(0.998, -0.0438),
|
||||
vec2(-0.345, -0.933),
|
||||
@ -96,7 +94,7 @@ void main() {
|
||||
return;
|
||||
}
|
||||
float material1f = textureLod(u_gbufferMaterialTexture, v_position2f, 0.0).a;
|
||||
material1f = 2.0 * material1f - COMPARE_GT_0_1(material1f, 0.5);
|
||||
material1f = 2.0 * material1f - step(0.5, material1f);
|
||||
if(material1f < 0.05) {
|
||||
return;
|
||||
}
|
||||
|
@ -47,21 +47,17 @@ void main() {
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 light;
|
||||
vec4 dlight;
|
||||
float blockLight = v_lightmap2f.x;
|
||||
float diffuse = 0.0;
|
||||
float len;
|
||||
if(u_dynamicLightCount1i > 0) {
|
||||
vec4 worldPosition4f = u_inverseViewMatrix4f * v_position4f;
|
||||
worldPosition4f.xyz /= worldPosition4f.w;
|
||||
int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i;
|
||||
for(int i = 0; i < safeLightCount; ++i) {
|
||||
light = u_dynamicLightArray[i];
|
||||
light.xyz = light.xyz - worldPosition4f.xyz;
|
||||
len = length(light.xyz);
|
||||
diffuse += max(light.w - len, 0.0);
|
||||
dlight = u_dynamicLightArray[i];
|
||||
dlight.xyz = dlight.xyz - worldPosition4f.xyz;
|
||||
blockLight = max((dlight.w - length(dlight.xyz)) * 0.066667, blockLight);
|
||||
}
|
||||
blockLight = min(blockLight + diffuse * 0.066667, 1.0);
|
||||
}
|
||||
|
||||
color *= texture(u_lightmapTexture, vec2(blockLight, v_lightmap2f.y));
|
||||
|
@ -146,25 +146,21 @@ void main() {
|
||||
#endif
|
||||
|
||||
#ifdef COMPILE_ENABLE_LIGHTMAP
|
||||
float diffuse = 0.0;
|
||||
#ifdef COMPILE_LIGHTMAP_ATTRIB
|
||||
float blockLight = v_lightmap2f.x;
|
||||
#else
|
||||
float blockLight = u_textureCoords02.x;
|
||||
#endif
|
||||
float len;
|
||||
vec4 light;
|
||||
vec4 dlight;
|
||||
if(u_dynamicLightCount1i > 0) {
|
||||
vec4 worldPosition4f = u_inverseViewMatrix4f * v_position4f;
|
||||
worldPosition4f.xyz /= worldPosition4f.w;
|
||||
int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i;
|
||||
for(int i = 0; i < safeLightCount; ++i) {
|
||||
light = u_dynamicLightArray[i];
|
||||
light.xyz = light.xyz - worldPosition4f.xyz;
|
||||
len = length(light.xyz);
|
||||
diffuse += max(light.w - len, 0.0);
|
||||
dlight = u_dynamicLightArray[i];
|
||||
dlight.xyz = dlight.xyz - worldPosition4f.xyz;
|
||||
blockLight = max((dlight.w - length(dlight.xyz)) * 0.066667, blockLight);
|
||||
}
|
||||
blockLight = min(blockLight + diffuse * 0.066667, 1.0);
|
||||
}
|
||||
#ifdef COMPILE_LIGHTMAP_ATTRIB
|
||||
color *= texture(u_samplerLightmap, vec2(blockLight, v_lightmap2f.y));
|
||||
@ -190,12 +186,8 @@ void main() {
|
||||
#endif
|
||||
|
||||
#ifdef COMPILE_ENABLE_MC_LIGHTING
|
||||
#ifndef COMPILE_ENABLE_LIGHTMAP
|
||||
vec4 light;
|
||||
float diffuse = 0.0;
|
||||
#else
|
||||
diffuse = 0.0;
|
||||
#endif
|
||||
for(int i = 0; i < u_lightsEnabled1i; ++i) {
|
||||
light = u_lightsDirections4fv[i];
|
||||
diffuse += max(dot(light.xyz, normal), 0.0) * light.w;
|
||||
|
BIN
sources/resources/assets/eagler/silence_loop.wav
Normal file
BIN
sources/resources/assets/eagler/silence_loop.wav
Normal file
Binary file not shown.
@ -40,6 +40,7 @@ dependencies {
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
entryCompression = ZipEntryCompression.STORED
|
||||
// TeaVM will fail if anything from platform-api is in the JAR
|
||||
fileTree("src/platform-api/java").visit {
|
||||
if (!isDirectory) {
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,7 +5,7 @@ import org.teavm.gradle.api.WasmDebugInfoLevel
|
||||
|
||||
plugins {
|
||||
id("java")
|
||||
id("org.teavm") version "0.12.0-EAGLER-R2"
|
||||
id("org.teavm") version "0.12.1-EAGLER-R3"
|
||||
|
||||
id("com.resentclient.oss.eaglercraft.build") version "0.0.0"
|
||||
}
|
||||
@ -36,7 +36,7 @@ repositories {
|
||||
dependencies {
|
||||
teavm(teavm.libs.jso)
|
||||
teavm(teavm.libs.jsoApis)
|
||||
compileOnly("org.teavm:teavm-core:0.12.0-EAGLER-R2") // workaround for a few hacks
|
||||
compileOnly("org.teavm:teavm-core:0.12.1-EAGLER-R3") // workaround for a few hacks
|
||||
implementation(rootProject)
|
||||
implementation(libs.jorbis)
|
||||
implementation(libs.bundles.common)
|
||||
|
Binary file not shown.
@ -1,8 +1,8 @@
|
||||
client-version-integer=51
|
||||
client-version-integer=52
|
||||
client-package-name=net.lax1dude.eaglercraft.v1_8.client
|
||||
client-origin-name=EaglercraftX
|
||||
client-origin-version=u51
|
||||
client-origin-version=u52
|
||||
client-origin-vendor=lax1dude
|
||||
client-fork-name=EaglercraftX
|
||||
client-fork-version=u51
|
||||
client-fork-version=u52
|
||||
client-fork-vendor=lax1dude
|
||||
|
@ -27,6 +27,8 @@ import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.dom.html.HTMLAudioElement;
|
||||
import org.teavm.jso.dom.html.HTMLSourceElement;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Int8Array;
|
||||
import org.teavm.jso.webaudio.AudioBuffer;
|
||||
@ -43,6 +45,7 @@ import org.teavm.jso.webaudio.PannerNode;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.JOrbisAudioBufferDecoder;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
@ -243,7 +246,25 @@ public class PlatformAudio {
|
||||
}
|
||||
|
||||
PlatformInput.clearEventBuffers();
|
||||
|
||||
|
||||
if(((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isKeepAliveHackTeaVM()) {
|
||||
byte[] silenceFile = PlatformAssets.getResourceBytes("/assets/eagler/silence_loop.wav");
|
||||
if (silenceFile != null) {
|
||||
HTMLAudioElement audio = (HTMLAudioElement) PlatformRuntime.doc.createElement("audio");
|
||||
audio.getClassList().add("_eaglercraftX_keepalive_hack");
|
||||
audio.setAttribute("style", "display:none;");
|
||||
audio.setAutoplay(true);
|
||||
audio.setLoop(true);
|
||||
HTMLSourceElement source = (HTMLSourceElement) PlatformRuntime.doc.createElement("source");
|
||||
source.setType("audio/wav");
|
||||
source.setSrc(TeaVMBlobURLManager.registerNewURLByte(silenceFile, "audio/wav").toExternalForm());
|
||||
audio.appendChild(source);
|
||||
audio.addEventListener("seeked", (e) -> {
|
||||
// NOP, wakes up the browser's event loop
|
||||
});
|
||||
PlatformRuntime.parent.appendChild(audio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JSBody(params = { "ctx" }, script = "var tmpBuf = ctx.createBuffer(2, 16, 16000); return (typeof tmpBuf.copyToChannel === \"function\");")
|
||||
|
@ -58,6 +58,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.InputEvent;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.LegacyKeycodeTranslator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.OffsetTouch;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.SortedTouchEvent;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLBackBuffer;
|
||||
|
||||
public class PlatformInput {
|
||||
@ -241,13 +242,9 @@ public class PlatformInput {
|
||||
|
||||
static boolean vsync = true;
|
||||
static boolean vsyncSupport = false;
|
||||
static boolean finish = true;
|
||||
|
||||
private static long vsyncWaiting = -1l;
|
||||
private static AsyncCallback<Void> vsyncAsyncCallback = null;
|
||||
private static int vsyncTimeout = -1;
|
||||
|
||||
// hack to fix occasional freeze on iOS
|
||||
private static int vsyncSaveLockInterval = -1;
|
||||
|
||||
@JSFunctor
|
||||
private static interface UnloadCallback extends JSObject {
|
||||
@ -723,8 +720,6 @@ public class PlatformInput {
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
|
||||
vsyncWaiting = -1l;
|
||||
vsyncAsyncCallback = null;
|
||||
vsyncTimeout = -1;
|
||||
vsyncSupport = false;
|
||||
|
||||
@ -735,39 +730,7 @@ public class PlatformInput {
|
||||
PlatformRuntime.logger.error("VSync is not supported on this browser!");
|
||||
}
|
||||
|
||||
if(vsyncSupport) {
|
||||
if(vsyncSaveLockInterval != -1) {
|
||||
try {
|
||||
Window.clearInterval(vsyncSaveLockInterval);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
vsyncSaveLockInterval = -1;
|
||||
}
|
||||
// fix for iOS freezing randomly...?
|
||||
vsyncSaveLockInterval = Window.setInterval(() -> {
|
||||
if(vsyncWaiting != -1l) {
|
||||
long steadyTime = PlatformRuntime.steadyTimeMillis();
|
||||
if(steadyTime - vsyncWaiting > 1000) {
|
||||
PlatformRuntime.logger.error("VSync lockup detected! Attempting to recover...");
|
||||
vsyncWaiting = -1l;
|
||||
if(vsyncTimeout != -1) {
|
||||
try {
|
||||
Window.clearTimeout(vsyncTimeout);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
vsyncTimeout = -1;
|
||||
}
|
||||
if(vsyncAsyncCallback != null) {
|
||||
AsyncCallback<Void> cb = vsyncAsyncCallback;
|
||||
vsyncAsyncCallback = null;
|
||||
cb.complete(null);
|
||||
}else {
|
||||
PlatformRuntime.logger.error("Async callback is null!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
finish = ((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isFinishOnSwapTeaVM();
|
||||
|
||||
try {
|
||||
gamepadSupported = gamepadSupported();
|
||||
@ -968,6 +931,9 @@ public class PlatformInput {
|
||||
syncTimer = 0.0;
|
||||
asyncRequestAnimationFrame();
|
||||
}else {
|
||||
if(finish) {
|
||||
PlatformOpenGL.ctx.finish();
|
||||
}
|
||||
if(fpsLimit <= 0 || fpsLimit > 1000) {
|
||||
syncTimer = 0.0;
|
||||
PlatformRuntime.swapDelayTeaVM();
|
||||
@ -1010,38 +976,27 @@ public class PlatformInput {
|
||||
private static native void asyncRequestAnimationFrame();
|
||||
|
||||
private static void asyncRequestAnimationFrame(AsyncCallback<Void> cb) {
|
||||
if(vsyncWaiting != -1l) {
|
||||
if(vsyncTimeout != -1) {
|
||||
cb.error(new IllegalStateException("Already waiting for vsync!"));
|
||||
return;
|
||||
}
|
||||
vsyncWaiting = PlatformRuntime.steadyTimeMillis();
|
||||
vsyncAsyncCallback = cb;
|
||||
final boolean[] hasTimedOut = new boolean[] { false };
|
||||
final int[] timeout = new int[] { -1 };
|
||||
Window.requestAnimationFrame((d) -> {
|
||||
if(!hasTimedOut[0]) {
|
||||
hasTimedOut[0] = true;
|
||||
if(vsyncWaiting != -1l) {
|
||||
vsyncWaiting = -1l;
|
||||
if(vsyncTimeout != -1 && vsyncTimeout == timeout[0]) {
|
||||
try {
|
||||
Window.clearTimeout(vsyncTimeout);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
vsyncTimeout = -1;
|
||||
}
|
||||
vsyncAsyncCallback = null;
|
||||
cb.complete(null);
|
||||
if(vsyncTimeout != -1) {
|
||||
Window.clearTimeout(vsyncTimeout);
|
||||
vsyncTimeout = -1;
|
||||
}
|
||||
cb.complete(null);
|
||||
}
|
||||
});
|
||||
vsyncTimeout = timeout[0] = Window.setTimeout(() -> {
|
||||
if(!hasTimedOut[0]) {
|
||||
hasTimedOut[0] = true;
|
||||
if(vsyncWaiting != -1l) {
|
||||
if(vsyncTimeout != -1) {
|
||||
vsyncTimeout = -1;
|
||||
vsyncWaiting = -1l;
|
||||
vsyncAsyncCallback = null;
|
||||
cb.complete(null);
|
||||
}
|
||||
}
|
||||
@ -1578,13 +1533,6 @@ public class PlatformInput {
|
||||
Window.clearTimeout(mouseUngrabTimeout);
|
||||
mouseUngrabTimeout = -1;
|
||||
}
|
||||
if(vsyncSaveLockInterval != -1) {
|
||||
try {
|
||||
Window.clearInterval(vsyncSaveLockInterval);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
vsyncSaveLockInterval = -1;
|
||||
}
|
||||
if(touchKeyboardField != null) {
|
||||
touchKeyboardField.blur();
|
||||
if(parent != null) {
|
||||
|
@ -32,6 +32,7 @@ import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.core.JSArrayReader;
|
||||
import org.teavm.jso.core.JSError;
|
||||
import org.teavm.jso.dom.css.CSSStyleDeclaration;
|
||||
import org.teavm.jso.dom.html.HTMLButtonElement;
|
||||
import org.teavm.jso.dom.html.HTMLCanvasElement;
|
||||
import org.teavm.jso.dom.html.HTMLDocument;
|
||||
import org.teavm.jso.dom.html.HTMLElement;
|
||||
@ -292,6 +293,46 @@ public class ClientMain {
|
||||
}
|
||||
}
|
||||
|
||||
private static HTMLElement createToolButtons(HTMLDocument doc) {
|
||||
HTMLButtonElement buttonResetSettings = (HTMLButtonElement) doc.createElement("button");
|
||||
buttonResetSettings.setAttribute("style", "margin-left:10px;");
|
||||
buttonResetSettings.setInnerText("Reset Settings");
|
||||
buttonResetSettings.addEventListener("click", (evt) -> {
|
||||
boolean y = false;
|
||||
if (Window.confirm("Do you want to reset client settings?")) {
|
||||
PlatformApplication.setLocalStorage("g", null);
|
||||
PlatformApplication.setLocalStorage("p", null);
|
||||
y = true;
|
||||
}
|
||||
if (Window.confirm("Do you want to reset servers and relays?")) {
|
||||
PlatformApplication.setLocalStorage("r", null);
|
||||
PlatformApplication.setLocalStorage("s", null);
|
||||
y = true;
|
||||
}
|
||||
if (y) {
|
||||
Window.alert("Settings reset.");
|
||||
}
|
||||
});
|
||||
HTMLButtonElement buttonOpenConsole = (HTMLButtonElement) doc.createElement("button");
|
||||
buttonOpenConsole.setAttribute("style", "margin-left:10px;");
|
||||
buttonOpenConsole.setInnerText("Open Debug Console");
|
||||
buttonOpenConsole.addEventListener("click", (evt) -> {
|
||||
DebugConsoleWindow.showDebugConsole();
|
||||
});
|
||||
HTMLElement div1 = doc.createElement("div");
|
||||
div1.setAttribute("style", "position:absolute;bottom:5px;right:0px;");
|
||||
div1.appendChild(buttonResetSettings);
|
||||
div1.appendChild(buttonOpenConsole);
|
||||
HTMLElement div2 = doc.createElement("div");
|
||||
div2.setAttribute("style", "position:relative;");
|
||||
div2.appendChild(div1);
|
||||
HTMLElement div3 = doc.createElement("div");
|
||||
div3.getClassList().add("_eaglercraftX_crash_tools_element");
|
||||
div3.setAttribute("style", "z-index:101;position:absolute;top:135px;left:10%;right:10%;height:0px;");
|
||||
div3.appendChild(div2);
|
||||
return div3;
|
||||
}
|
||||
|
||||
public static void showCrashScreen(String message, Throwable t) {
|
||||
try {
|
||||
showCrashScreen(message + "\n\n" + EagRuntime.getStackTrace(t));
|
||||
@ -410,6 +451,7 @@ public class ClientMain {
|
||||
div.getClassList().add("_eaglercraftX_crash_element");
|
||||
el.appendChild(img);
|
||||
el.appendChild(div);
|
||||
el.appendChild(createToolButtons(doc));
|
||||
div.appendChild(doc.createTextNode(strFinal));
|
||||
|
||||
PlatformRuntime.removeEventHandlers();
|
||||
@ -581,6 +623,7 @@ public class ClientMain {
|
||||
div.getClassList().add("_eaglercraftX_incompatible_element");
|
||||
el.appendChild(img);
|
||||
el.appendChild(div);
|
||||
el.appendChild(createToolButtons(doc));
|
||||
div.setInnerHTML("<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg>+ This device is incompatible with Eaglercraft :(</h2>"
|
||||
+ "<div style=\"margin-left:40px;\">"
|
||||
+ "<p style=\"font-size:1.2em;\"><b style=\"font-size:1.1em;\">Issue:</b> <span style=\"color:#BB0000;\" id=\"_eaglercraftX_crashReason\"></span><br /></p>"
|
||||
@ -664,14 +707,17 @@ public class ClientMain {
|
||||
div.getClassList().add("_eaglercraftX_context_lost_element");
|
||||
el.appendChild(img);
|
||||
el.appendChild(div);
|
||||
el.appendChild(createToolButtons(doc));
|
||||
div.setInnerHTML("<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg> + WebGL context lost!</h2>"
|
||||
+ "<div style=\"margin-left:40px;\">"
|
||||
+ "<p style=\"font-size:1.2em;\">Your browser has forcibly released all of the resources "
|
||||
+ "allocated by the game's 3D rendering context. EaglercraftX cannot continue, please refresh "
|
||||
+ "the page to restart the game.</p>"
|
||||
+ "the page to restart the game, sorry for the inconvenience.</p>"
|
||||
+ "<p style=\"font-size:1.2em;\">This is not a bug, it is usually caused by the browser "
|
||||
+ "deciding it no longer has sufficient resources to continue rendering this page. If it "
|
||||
+ "happens again, try closing your other browser tabs and windows.</p>"
|
||||
+ "<p style=\"font-size:1.2em;\">If you're playing with vsync disabled, try enabling vsync "
|
||||
+ "to allow the browser to control the GPU usage more precisely.</p>"
|
||||
+ "<p style=\"overflow-wrap:break-word;white-space:pre-wrap;font:0.75em monospace;margin-top:1.5em;\" id=\"_eaglercraftX_contextLostTrace\"></p>"
|
||||
+ "</div>");
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
@ -27,13 +28,15 @@ import com.jcraft.jzlib.CRC32;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.IOUtils;
|
||||
|
||||
public class EPKLoader {
|
||||
|
||||
public static final void loadEPK(ArrayBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
public static void loadEPK(ArrayBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
loadEPK(epkFile, "", loadedFiles);
|
||||
}
|
||||
|
||||
public static final void loadEPK(ArrayBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
public static void loadEPK(ArrayBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
int byteLength = epkFile.getByteLength();
|
||||
int l = byteLength - 16;
|
||||
if(l < 1) {
|
||||
@ -43,7 +46,7 @@ public class EPKLoader {
|
||||
ArrayBufferInputStream is = new ArrayBufferInputStream(epkFile, 0, byteLength - 8);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
is.read(header);
|
||||
IOUtils.readFully(is, header);
|
||||
String type = readASCII(header);
|
||||
|
||||
if(!"EAGPKG$$".equals(type)) {
|
||||
@ -65,13 +68,13 @@ public class EPKLoader {
|
||||
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||
}
|
||||
|
||||
is.skip(is.read()); // skip filename
|
||||
is.skip(loadShort(is)); // skip comment
|
||||
is.skip(8); // skip millis date
|
||||
IOUtils.skipFully(is, loadByte(is)); // skip filename
|
||||
IOUtils.skipFully(is, loadShort(is)); // skip comment
|
||||
IOUtils.skipFully(is, 8); // skip millis date
|
||||
|
||||
int numFiles = loadInt(is);
|
||||
|
||||
char compressionType = (char)is.read();
|
||||
char compressionType = (char)loadByte(is);
|
||||
|
||||
InputStream zis;
|
||||
switch(compressionType) {
|
||||
@ -112,11 +115,11 @@ public class EPKLoader {
|
||||
if(i == 0) {
|
||||
if(blockType == blockHead) {
|
||||
byte[] readType = new byte[len];
|
||||
zis.read(readType);
|
||||
IOUtils.readFully(zis, readType);
|
||||
if(!"file-type".equals(name) || !"epk/resources".equals(readASCII(readType))) {
|
||||
throw new IOException("EPK is not of file-type 'epk/resources'!");
|
||||
}
|
||||
if(zis.read() != '>') {
|
||||
if(loadByte(zis) != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
continue;
|
||||
@ -133,7 +136,7 @@ public class EPKLoader {
|
||||
int expectedCRC = loadInt(zis);
|
||||
|
||||
byte[] load = new byte[len - 5];
|
||||
zis.read(load);
|
||||
IOUtils.readFully(zis, load);
|
||||
|
||||
if(len > 5) {
|
||||
crc32.reset();
|
||||
@ -143,16 +146,16 @@ public class EPKLoader {
|
||||
}
|
||||
}
|
||||
|
||||
if(zis.read() != ':') {
|
||||
if(loadByte(zis) != ':') {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
loadedFiles.put(path + name, load);
|
||||
}else {
|
||||
zis.skip(len);
|
||||
IOUtils.skipFully(zis, len);
|
||||
}
|
||||
|
||||
if(zis.read() != '>') {
|
||||
if(loadByte(zis) != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
}
|
||||
@ -163,28 +166,36 @@ public class EPKLoader {
|
||||
|
||||
zis.close();
|
||||
}
|
||||
|
||||
private static final int loadShort(InputStream is) throws IOException {
|
||||
return (is.read() << 8) | is.read();
|
||||
|
||||
private static int loadByte(InputStream is) throws IOException {
|
||||
int i = is.read();
|
||||
if (i < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private static final int loadInt(InputStream is) throws IOException {
|
||||
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||
|
||||
private static int loadShort(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
private static final String readASCII(byte[] bytesIn) throws IOException {
|
||||
|
||||
private static int loadInt(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 24) | (loadByte(is) << 16) | (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
private static String readASCII(byte[] bytesIn) throws IOException {
|
||||
char[] charIn = new char[bytesIn.length];
|
||||
for(int i = 0; i < bytesIn.length; ++i) {
|
||||
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
private static final String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = bytesIn.read();
|
||||
|
||||
private static String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = loadByte(bytesIn);
|
||||
char[] charIn = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||
charIn[i] = (char)loadByte(bytesIn);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
@ -67,9 +67,6 @@ public class PCMToWAVLoader {
|
||||
if (val < -32768) {
|
||||
val = -32768;
|
||||
}
|
||||
if (val < 0) {
|
||||
val |= 32768;
|
||||
}
|
||||
bufferOut.putShort((short)val);
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,8 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
private boolean ramdiskMode = false;
|
||||
private boolean singleThreadMode = false;
|
||||
private boolean enableEPKVersionCheck = true;
|
||||
private boolean keepAliveHack = true;
|
||||
private boolean finishOnSwap = true;
|
||||
|
||||
public void loadNative(JSObject jsObject) {
|
||||
integratedServerOpts = new JSONObject();
|
||||
@ -139,6 +141,8 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
ramdiskMode = eaglercraftXOpts.getRamdiskMode(false);
|
||||
singleThreadMode = eaglercraftXOpts.getSingleThreadMode(false);
|
||||
enableEPKVersionCheck = eaglercraftXOpts.getEnableEPKVersionCheck(true);
|
||||
keepAliveHack = eaglercraftXOpts.getKeepAliveHack(true);
|
||||
finishOnSwap = eaglercraftXOpts.getFinishOnSwap(true);
|
||||
JSEaglercraftXOptsHooks hooksObj = eaglercraftXOpts.getHooks();
|
||||
if(hooksObj != null) {
|
||||
hooks.loadHooks(hooksObj);
|
||||
@ -270,6 +274,8 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
ramdiskMode = eaglercraftOpts.optBoolean("ramdiskMode", false);
|
||||
singleThreadMode = eaglercraftOpts.optBoolean("singleThreadMode", false);
|
||||
enableEPKVersionCheck = eaglercraftOpts.optBoolean("enableEPKVersionCheck", true);
|
||||
keepAliveHack = eaglercraftOpts.optBoolean("keepAliveHack", true);
|
||||
finishOnSwap = eaglercraftOpts.optBoolean("finishOnSwap", true);
|
||||
defaultServers.clear();
|
||||
JSONArray serversArray = eaglercraftOpts.optJSONArray("servers");
|
||||
if(serversArray != null) {
|
||||
@ -556,6 +562,14 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isKeepAliveHackTeaVM() {
|
||||
return keepAliveHack;
|
||||
}
|
||||
|
||||
public boolean isFinishOnSwapTeaVM() {
|
||||
return finishOnSwap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
@ -608,6 +622,8 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
jsonObject.put("ramdiskMode", ramdiskMode);
|
||||
jsonObject.put("singleThreadMode", singleThreadMode);
|
||||
jsonObject.put("enableEPKVersionCheck", enableEPKVersionCheck);
|
||||
jsonObject.put("keepAliveHack", keepAliveHack);
|
||||
jsonObject.put("finishOnSwap", finishOnSwap);
|
||||
JSONArray serversArr = new JSONArray();
|
||||
for(int i = 0, l = defaultServers.size(); i < l; ++i) {
|
||||
DefaultServer srv = defaultServers.get(i);
|
||||
|
@ -149,10 +149,14 @@ public class TeaVMClientConfigAdapterHooks implements IClientConfigAdapterHooks
|
||||
}
|
||||
|
||||
public void loadHooks(JSEaglercraftXOptsHooks hooks) {
|
||||
saveHook = (LocalStorageSaveHook)hooks.getLocalStorageSavedHook();
|
||||
loadHook = (LocalStorageLoadHook)hooks.getLocalStorageLoadedHook();
|
||||
crashHook = (CrashReportHook)hooks.getCrashReportHook();
|
||||
screenChangedHook = (ScreenChangeHook)hooks.getScreenChangedHook();
|
||||
JSObject obj = hooks.getLocalStorageSavedHook();
|
||||
saveHook = obj != null ? (LocalStorageSaveHook) obj : null;
|
||||
obj = hooks.getLocalStorageLoadedHook();
|
||||
loadHook = obj != null ? (LocalStorageLoadHook) obj : null;
|
||||
obj = hooks.getCrashReportHook();
|
||||
crashHook = obj != null ? (CrashReportHook) obj : null;
|
||||
obj = hooks.getScreenChangedHook();
|
||||
screenChangedHook = obj != null ? (ScreenChangeHook) obj : null;
|
||||
}
|
||||
|
||||
}
|
@ -178,4 +178,10 @@ public abstract class JSEaglercraftXOptsRoot implements JSObject {
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableEPKVersionCheck === \"boolean\") ? this.enableEPKVersionCheck : def;")
|
||||
public native boolean getEnableEPKVersionCheck(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.keepAliveHack === \"boolean\") ? this.keepAliveHack : def;")
|
||||
public native boolean getKeepAliveHack(boolean keepAliveHack);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.finishOnSwap === \"boolean\") ? this.finishOnSwap : def;")
|
||||
public native boolean getFinishOnSwap(boolean finishOnSwap);
|
||||
|
||||
}
|
@ -24,6 +24,7 @@ import java.util.Date;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.browser.Storage;
|
||||
@ -43,6 +44,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.MemoryStack;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.ClientMain;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.TeaVMUtils;
|
||||
|
||||
public class PlatformApplication {
|
||||
@ -174,7 +176,23 @@ public class PlatformApplication {
|
||||
}
|
||||
}
|
||||
|
||||
public static final void displayFileChooser(String mime, String ext) {
|
||||
public static void setResetSettingsCallbackWASM() {
|
||||
setResetSettingsCallbackWASM0().call(ClientMain::resetSettings);
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface JSWASMResetSettingsCallback extends JSObject {
|
||||
void callback();
|
||||
}
|
||||
|
||||
private static interface JSWASMResetSettingsCallbackInterface extends JSObject {
|
||||
void call(JSWASMResetSettingsCallback callback);
|
||||
}
|
||||
|
||||
@Import(module = "platformApplication", name = "setResetSettingsCallback")
|
||||
private static native JSWASMResetSettingsCallbackInterface setResetSettingsCallbackWASM0();
|
||||
|
||||
public static void displayFileChooser(String mime, String ext) {
|
||||
displayFileChooser0(BetterJSStringConverter.stringToJS(mime), BetterJSStringConverter.stringToJS(ext));
|
||||
}
|
||||
|
||||
|
@ -94,11 +94,26 @@ public class PlatformAudio {
|
||||
logger.error("OGG file support detected as false! Using embedded JOrbis OGG decoder");
|
||||
}
|
||||
}
|
||||
|
||||
if(((WASMGCClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isKeepAliveHackTeaVM()) {
|
||||
byte[] silenceFile = PlatformAssets.getResourceBytes("/assets/eagler/silence_loop.wav");
|
||||
if (silenceFile != null) {
|
||||
MemoryStack.push();
|
||||
try {
|
||||
initKeepAliveHack(WASMGCDirectArrayConverter.byteArrayToStackU8Array(silenceFile));
|
||||
}finally {
|
||||
MemoryStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformAudio", name = "getContext")
|
||||
private static native AudioContext getContext();
|
||||
|
||||
@Import(module = "platformAudio", name = "initKeepAliveHack")
|
||||
private static native void initKeepAliveHack(Uint8Array array);
|
||||
|
||||
protected static class BrowserAudioResource implements IAudioResource {
|
||||
|
||||
protected AudioBuffer buffer;
|
||||
@ -356,11 +371,8 @@ public class PlatformAudio {
|
||||
return audioctx != null;
|
||||
}
|
||||
|
||||
@JSBody(params = { "node" }, script = "node.distanceModel = \"linear\";")
|
||||
static native void setDistanceModelLinearFast(PannerNode node) ;
|
||||
|
||||
@JSBody(params = { "node" }, script = "node.panningModel = \"HRTF\";")
|
||||
static native void setPanningModelHRTFFast(PannerNode node) ;
|
||||
@Import(module = "platformAudio", name = "setupPanner")
|
||||
static native void setupPanner(PannerNode node, float maxDist, float x, float y, float z);
|
||||
|
||||
public static IAudioHandle beginPlayback(IAudioResource track, float x, float y, float z,
|
||||
float volume, float pitch, boolean repeat) {
|
||||
@ -373,17 +385,10 @@ public class PlatformAudio {
|
||||
src.setLoop(repeat);
|
||||
|
||||
PannerNode panner = audioctx.createPanner();
|
||||
panner.setPosition(x, y, z);
|
||||
|
||||
float v1 = volume * 16.0f;
|
||||
if(v1 < 16.0f) v1 = 16.0f;
|
||||
panner.setMaxDistance(v1);
|
||||
panner.setRolloffFactor(1.0f);
|
||||
setDistanceModelLinearFast(panner);
|
||||
setPanningModelHRTFFast(panner);
|
||||
panner.setConeInnerAngle(360.0f);
|
||||
panner.setConeOuterAngle(0.0f);
|
||||
panner.setConeOuterGain(0.0f);
|
||||
panner.setOrientation(0.0f, 1.0f, 0.0f);
|
||||
setupPanner(panner, v1, x, y, z);
|
||||
|
||||
GainNode gain = audioctx.createGain();
|
||||
float v2 = volume;
|
||||
@ -396,7 +401,7 @@ public class PlatformAudio {
|
||||
if(gameRecGain != null) {
|
||||
gain.connect(gameRecGain);
|
||||
}
|
||||
|
||||
|
||||
src.start();
|
||||
|
||||
BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, panner, gain, pitch, repeat);
|
||||
|
@ -113,6 +113,7 @@ public class PlatformInput {
|
||||
|
||||
static boolean vsync = true;
|
||||
static boolean vsyncSupport = false;
|
||||
static boolean finish = true;
|
||||
|
||||
private static Map<String, LegacyKeycodeTranslator.LegacyKeycode> keyCodeTranslatorMap = null;
|
||||
|
||||
@ -125,6 +126,7 @@ public class PlatformInput {
|
||||
fullscreenSupported = supportsFullscreen0();
|
||||
vsyncSupport = isVSyncSupported0();
|
||||
WASMGCClientConfigAdapter conf = (WASMGCClientConfigAdapter)PlatformRuntime.getClientConfigAdapter();
|
||||
finish = conf.isFinishOnSwapTeaVM();
|
||||
useVisualViewport = conf.isUseVisualViewportTeaVM() && isVisualViewport0();
|
||||
lastWasResizedWindowWidth = -2;
|
||||
lastWasResizedWindowHeight = -2;
|
||||
@ -656,7 +658,7 @@ public class PlatformInput {
|
||||
PlatformScreenRecord.captureFrameHook();
|
||||
}
|
||||
|
||||
updatePlatformAndSleep(fpsLimit, vsync && vsyncSupport);// && vsync
|
||||
updatePlatformAndSleep(fpsLimit, vsync && vsyncSupport, finish);
|
||||
PlatformRuntime.pollJSEventsAfterSleep();
|
||||
}
|
||||
|
||||
@ -664,7 +666,7 @@ public class PlatformInput {
|
||||
private static native void updateCanvasSize(int width, int height);
|
||||
|
||||
@Import(module = "platformInput", name = "updatePlatformAndSleep")
|
||||
private static native void updatePlatformAndSleep(int fpsLimit, boolean vsync);
|
||||
private static native void updatePlatformAndSleep(int fpsLimit, boolean vsync, boolean finish);
|
||||
|
||||
public static boolean isVSyncSupported() {
|
||||
return vsyncSupport;
|
||||
|
@ -79,6 +79,7 @@ public class PlatformRuntime {
|
||||
canvas = getCanvasElement();
|
||||
printMemoryStackAddrWASMGC();
|
||||
PlatformApplication.setMCServerWindowGlobal(null);
|
||||
PlatformApplication.setResetSettingsCallbackWASM();
|
||||
PlatformOpenGL.initContext();
|
||||
PlatformInput.initContext(win, parent, canvas);
|
||||
|
||||
|
@ -215,16 +215,8 @@ public class PlatformVoiceClient {
|
||||
audioNode.disconnect(gain);
|
||||
}
|
||||
panner = PlatformAudio.audioctx.createPanner();
|
||||
panner.setRolloffFactor(1f);
|
||||
PlatformAudio.setDistanceModelLinearFast(panner);
|
||||
PlatformAudio.setPanningModelHRTFFast(panner);
|
||||
panner.setConeInnerAngle(360f);
|
||||
panner.setConeOuterAngle(0f);
|
||||
panner.setConeOuterGain(0f);
|
||||
panner.setOrientation(0f, 1f, 0f);
|
||||
panner.setPosition(0, 0, 0);
|
||||
float vol = VoiceClientController.getVoiceListenVolume();
|
||||
panner.setMaxDistance(vol * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
|
||||
PlatformAudio.setupPanner(panner, vol * 2 * VoiceClientController.getVoiceProximity() + 0.1f, 0, 0, 0);
|
||||
gain = PlatformAudio.audioctx.createGain();
|
||||
gain.getGain().setValue(vol);
|
||||
audioNode.connect(gain);
|
||||
|
@ -30,22 +30,26 @@ public class BetterJSStringConverter {
|
||||
|
||||
@Unmanaged
|
||||
public static JSString stringToJS(String input) {
|
||||
if (input == null) return null;
|
||||
return (JSString) JS.wrap(input);
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
@SuppressWarnings("unchecked")
|
||||
public static JSArray<JSString> stringArrayToJS(String[] input) {
|
||||
if (input == null) return null;
|
||||
return (JSArray<JSString>) JS.wrap(input);
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static String stringFromJS(JSString input) {
|
||||
if (input == null) return null;
|
||||
return JS.unwrapString(input);
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static String[] stringArrayFromJS(JSArray<JSString> input) {
|
||||
if (input == null) return null;
|
||||
return JS.unwrapStringArray(input);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import org.teavm.jso.browser.Window;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.ContextLostError;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.opts.JSEaglercraftXOptsRoot;
|
||||
import net.minecraft.client.main.Main;
|
||||
@ -98,6 +99,25 @@ public class ClientMain {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined here to match the JS runtime
|
||||
*/
|
||||
public static void resetSettings() {
|
||||
boolean y = false;
|
||||
if (Window.confirm("Do you want to reset client settings?")) {
|
||||
PlatformApplication.setLocalStorage("g", null);
|
||||
PlatformApplication.setLocalStorage("p", null);
|
||||
y = true;
|
||||
}
|
||||
if (Window.confirm("Do you want to reset servers and relays?")) {
|
||||
PlatformApplication.setLocalStorage("r", null);
|
||||
PlatformApplication.setLocalStorage("s", null);
|
||||
y = true;
|
||||
}
|
||||
if (y) {
|
||||
Window.alert("Settings reset.");
|
||||
}
|
||||
}
|
||||
|
||||
@Import(module = "platformRuntime", name = "getEaglercraftXOpts")
|
||||
private static native JSObject getEaglerXOpts();
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
@ -24,16 +25,17 @@ import com.jcraft.jzlib.CRC32;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.IOUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerBufferInputStream;
|
||||
|
||||
public class EPKLoader {
|
||||
|
||||
public static final void loadEPK(ByteBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
public static void loadEPK(ByteBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
loadEPK(epkFile, "", loadedFiles);
|
||||
}
|
||||
|
||||
public static final void loadEPK(ByteBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
public static void loadEPK(ByteBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
int byteLength = epkFile.remaining();
|
||||
int l = byteLength - 16;
|
||||
if(l < 1) {
|
||||
@ -43,7 +45,7 @@ public class EPKLoader {
|
||||
EaglerBufferInputStream is = new EaglerBufferInputStream(epkFile);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
is.read(header);
|
||||
IOUtils.readFully(is, header);
|
||||
String type = readASCII(header);
|
||||
|
||||
if(!"EAGPKG$$".equals(type)) {
|
||||
@ -65,13 +67,13 @@ public class EPKLoader {
|
||||
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||
}
|
||||
|
||||
is.skip(is.read()); // skip filename
|
||||
is.skip(loadShort(is)); // skip comment
|
||||
is.skip(8); // skip millis date
|
||||
IOUtils.skipFully(is, loadByte(is)); // skip filename
|
||||
IOUtils.skipFully(is, loadShort(is)); // skip comment
|
||||
IOUtils.skipFully(is, 8); // skip millis date
|
||||
|
||||
int numFiles = loadInt(is);
|
||||
|
||||
char compressionType = (char)is.read();
|
||||
char compressionType = (char)loadByte(is);
|
||||
|
||||
InputStream zis;
|
||||
switch(compressionType) {
|
||||
@ -112,11 +114,11 @@ public class EPKLoader {
|
||||
if(i == 0) {
|
||||
if(blockType == blockHead) {
|
||||
byte[] readType = new byte[len];
|
||||
zis.read(readType);
|
||||
IOUtils.readFully(zis, readType);
|
||||
if(!"file-type".equals(name) || !"epk/resources".equals(readASCII(readType))) {
|
||||
throw new IOException("EPK is not of file-type 'epk/resources'!");
|
||||
}
|
||||
if(zis.read() != '>') {
|
||||
if(loadByte(zis) != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
continue;
|
||||
@ -133,7 +135,7 @@ public class EPKLoader {
|
||||
int expectedCRC = loadInt(zis);
|
||||
|
||||
byte[] load = new byte[len - 5];
|
||||
zis.read(load);
|
||||
IOUtils.readFully(zis, load);
|
||||
|
||||
if(len > 5) {
|
||||
crc32.reset();
|
||||
@ -143,16 +145,16 @@ public class EPKLoader {
|
||||
}
|
||||
}
|
||||
|
||||
if(zis.read() != ':') {
|
||||
if(loadByte(zis) != ':') {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
loadedFiles.put(path + name, load);
|
||||
}else {
|
||||
zis.skip(len);
|
||||
IOUtils.skipFully(zis, len);
|
||||
}
|
||||
|
||||
if(zis.read() != '>') {
|
||||
if(loadByte(zis) != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
}
|
||||
@ -163,28 +165,36 @@ public class EPKLoader {
|
||||
|
||||
zis.close();
|
||||
}
|
||||
|
||||
private static final int loadShort(InputStream is) throws IOException {
|
||||
return (is.read() << 8) | is.read();
|
||||
|
||||
private static int loadByte(InputStream is) throws IOException {
|
||||
int i = is.read();
|
||||
if (i < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private static final int loadInt(InputStream is) throws IOException {
|
||||
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||
|
||||
private static int loadShort(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
private static final String readASCII(byte[] bytesIn) throws IOException {
|
||||
|
||||
private static int loadInt(InputStream is) throws IOException {
|
||||
return (loadByte(is) << 24) | (loadByte(is) << 16) | (loadByte(is) << 8) | loadByte(is);
|
||||
}
|
||||
|
||||
private static String readASCII(byte[] bytesIn) throws IOException {
|
||||
char[] charIn = new char[bytesIn.length];
|
||||
for(int i = 0; i < bytesIn.length; ++i) {
|
||||
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
private static final String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = bytesIn.read();
|
||||
|
||||
private static String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = loadByte(bytesIn);
|
||||
char[] charIn = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||
charIn[i] = (char)loadByte(bytesIn);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
@ -82,6 +82,8 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
private boolean ramdiskMode = false;
|
||||
private boolean singleThreadMode = false;
|
||||
private boolean enforceVSync = true;
|
||||
private boolean keepAliveHack = true;
|
||||
private boolean finishOnSwap = true;
|
||||
|
||||
public void loadNative(JSObject jsObject) {
|
||||
JSEaglercraftXOptsRoot eaglercraftXOpts = (JSEaglercraftXOptsRoot)jsObject;
|
||||
@ -124,6 +126,8 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
ramdiskMode = eaglercraftXOpts.getRamdiskMode(false);
|
||||
singleThreadMode = eaglercraftXOpts.getSingleThreadMode(false);
|
||||
enforceVSync = eaglercraftXOpts.getEnforceVSync(true);
|
||||
keepAliveHack = eaglercraftXOpts.getKeepAliveHack(true);
|
||||
finishOnSwap = eaglercraftXOpts.getFinishOnSwap(true);
|
||||
JSEaglercraftXOptsHooks hooksObj = eaglercraftXOpts.getHooks();
|
||||
if(hooksObj != null) {
|
||||
hooks.loadHooks(hooksObj);
|
||||
@ -400,6 +404,14 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
return enforceVSync;
|
||||
}
|
||||
|
||||
public boolean isKeepAliveHackTeaVM() {
|
||||
return keepAliveHack;
|
||||
}
|
||||
|
||||
public boolean isFinishOnSwapTeaVM() {
|
||||
return finishOnSwap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
@ -446,6 +458,8 @@ public class WASMGCClientConfigAdapter implements IClientConfigAdapter {
|
||||
jsonObject.put("ramdiskMode", ramdiskMode);
|
||||
jsonObject.put("singleThreadMode", singleThreadMode);
|
||||
jsonObject.put("enforceVSync", enforceVSync);
|
||||
jsonObject.put("keepAliveHack", keepAliveHack);
|
||||
jsonObject.put("finishOnSwap", finishOnSwap);
|
||||
JSONArray serversArr = new JSONArray();
|
||||
for(int i = 0, l = defaultServers.size(); i < l; ++i) {
|
||||
DefaultServer srv = defaultServers.get(i);
|
||||
|
@ -114,10 +114,14 @@ public class WASMGCClientConfigAdapterHooks implements IClientConfigAdapterHooks
|
||||
}
|
||||
|
||||
public void loadHooks(JSEaglercraftXOptsHooks hooks) {
|
||||
saveHook = (LocalStorageSaveHook)hooks.getLocalStorageSavedHook();
|
||||
loadHook = (LocalStorageLoadHook)hooks.getLocalStorageLoadedHook();
|
||||
crashHook = (CrashReportHook)hooks.getCrashReportHook();
|
||||
screenChangedHook = (ScreenChangeHook)hooks.getScreenChangedHook();
|
||||
JSObject obj = hooks.getLocalStorageSavedHook();
|
||||
saveHook = obj != null ? (LocalStorageSaveHook) obj : null;
|
||||
obj = hooks.getLocalStorageLoadedHook();
|
||||
loadHook = obj != null ? (LocalStorageLoadHook) obj : null;
|
||||
obj = hooks.getCrashReportHook();
|
||||
crashHook = obj != null ? (CrashReportHook) obj : null;
|
||||
obj = hooks.getScreenChangedHook();
|
||||
screenChangedHook = obj != null ? (ScreenChangeHook) obj : null;
|
||||
}
|
||||
|
||||
}
|
@ -172,4 +172,10 @@ public interface JSEaglercraftXOptsRoot extends JSObject {
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.enableEPKVersionCheck === \"boolean\") ? this.enableEPKVersionCheck : def;")
|
||||
boolean getEnableEPKVersionCheck(boolean deobfStackTraces);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.keepAliveHack === \"boolean\") ? this.keepAliveHack : def;")
|
||||
boolean getKeepAliveHack(boolean keepAliveHack);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.finishOnSwap === \"boolean\") ? this.finishOnSwap : def;")
|
||||
boolean getFinishOnSwap(boolean finishOnSwap);
|
||||
|
||||
}
|
@ -100,6 +100,12 @@ var isCrashed = false;
|
||||
const crashReportStrings = [];
|
||||
/** @type {function()|null} */
|
||||
var removeEventHandlers = null;
|
||||
/** @type {function()|null} */
|
||||
var keepAliveCallback = null;
|
||||
/** @type {function()|null} */
|
||||
var showDebugConsole = null;
|
||||
/** @type {function()|null} */
|
||||
var resetSettings = null;
|
||||
|
||||
const runtimeOpts = {
|
||||
localStorageNamespace: "_eaglercraftX",
|
||||
@ -530,6 +536,44 @@ function deobfuscateStack(stack) {
|
||||
return stackFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
function createToolButtons() {
|
||||
const buttonResetSettings = /** @type {HTMLButtonElement} */ (document.createElement("button"));
|
||||
buttonResetSettings.setAttribute("style", "margin-left:10px;");
|
||||
buttonResetSettings.innerText = "Reset Settings";
|
||||
buttonResetSettings.addEventListener("click", function(/** Event */ evt) {
|
||||
if (resetSettings) {
|
||||
resetSettings();
|
||||
} else {
|
||||
window.alert("Local storage has not been initialized yet");
|
||||
}
|
||||
});
|
||||
const buttonOpenConsole = /** @type {HTMLButtonElement} */ (document.createElement("button"));
|
||||
buttonOpenConsole.setAttribute("style", "margin-left:10px;");
|
||||
buttonOpenConsole.innerText = "Open Debug Console";
|
||||
buttonOpenConsole.addEventListener("click", function(/** Event */ evt) {
|
||||
if (showDebugConsole) {
|
||||
showDebugConsole();
|
||||
} else {
|
||||
window.alert("Debug console has not been initialized yet");
|
||||
}
|
||||
});
|
||||
const div1 = /** @type {HTMLElement} */ (document.createElement("div"));
|
||||
div1.setAttribute("style", "position:absolute;bottom:5px;right:0px;");
|
||||
div1.appendChild(buttonResetSettings);
|
||||
div1.appendChild(buttonOpenConsole);
|
||||
const div2 = /** @type {HTMLElement} */ (document.createElement("div"));
|
||||
div2.setAttribute("style", "position:relative;");
|
||||
div2.appendChild(div1);
|
||||
const div3 = /** @type {HTMLElement} */ (document.createElement("div"));
|
||||
div3.classList.add("_eaglercraftX_crash_tools_element");
|
||||
div3.setAttribute("style", "z-index:101;position:absolute;top:135px;left:10%;right:10%;height:0px;");
|
||||
div3.appendChild(div2);
|
||||
return div3;
|
||||
}
|
||||
|
||||
function displayUncaughtCrashReport(error) {
|
||||
const stack = error ? deobfuscateStack(error.stack) : null;
|
||||
const crashContent = "Native Browser Exception\n" +
|
||||
@ -657,6 +701,7 @@ function displayCrashReport(crashReport, enablePrint) {
|
||||
div.classList.add("_eaglercraftX_crash_element");
|
||||
parentEl.appendChild(img);
|
||||
parentEl.appendChild(div);
|
||||
parentEl.appendChild(createToolButtons());
|
||||
div.appendChild(document.createTextNode(strFinal));
|
||||
|
||||
if(removeEventHandlers) removeEventHandlers();
|
||||
@ -709,6 +754,7 @@ function showIncompatibleScreen(msg) {
|
||||
div.classList.add("_eaglercraftX_incompatible_element");
|
||||
parentEl.appendChild(img);
|
||||
parentEl.appendChild(div);
|
||||
parentEl.appendChild(createToolButtons());
|
||||
div.innerHTML = "<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg>+ This device is incompatible with Eaglercraft :(</h2>"
|
||||
+ "<div style=\"margin-left:40px;\">"
|
||||
+ "<p style=\"font-size:1.2em;\"><b style=\"font-size:1.1em;\">Issue:</b> <span style=\"color:#BB0000;\" id=\"_eaglercraftX_crashReason\"></span><br /></p>"
|
||||
@ -785,14 +831,17 @@ function showContextLostScreen(msg) {
|
||||
div.classList.add("_eaglercraftX_context_lost_element");
|
||||
parentEl.appendChild(img);
|
||||
parentEl.appendChild(div);
|
||||
parentEl.appendChild(createToolButtons());
|
||||
div.innerHTML = "<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg> + WebGL context lost!</h2>"
|
||||
+ "<div style=\"margin-left:40px;\">"
|
||||
+ "<p style=\"font-size:1.2em;\">Your browser has forcibly released all of the resources "
|
||||
+ "allocated by the game's 3D rendering context. EaglercraftX cannot continue, please refresh "
|
||||
+ "the page to restart the game.</p>"
|
||||
+ "the page to restart the game, sorry for the inconvenience.</p>"
|
||||
+ "<p style=\"font-size:1.2em;\">This is not a bug, it is usually caused by the browser "
|
||||
+ "deciding it no longer has sufficient resources to continue rendering this page. If it "
|
||||
+ "happens again, try closing your other browser tabs and windows.</p>"
|
||||
+ "<p style=\"font-size:1.2em;\">If you're playing with vsync disabled, try enabling vsync "
|
||||
+ "to allow the browser to control the GPU usage more precisely.</p>"
|
||||
+ "<p style=\"overflow-wrap:break-word;white-space:pre-wrap;font:0.75em monospace;margin-top:1.5em;\" id=\"_eaglercraftX_contextLostTrace\"></p>"
|
||||
+ "</div>";
|
||||
|
||||
|
@ -328,7 +328,7 @@ function initializePlatfApplication(applicationImports) {
|
||||
/** @type {HTMLElement} */
|
||||
var loggerMessageContainer = null;
|
||||
/** @type {string} */
|
||||
const loggerLocalStorageKey = runtimeOpts.localStorageNamespace + "showDebugConsole";
|
||||
const loggerLocalStorageKey = runtimeOpts.localStorageNamespace + ".showDebugConsole";
|
||||
/** @type {string} */
|
||||
const loggerWinUnloadEvent = runtimeOpts.fixDebugConsoleUnloadListener ? "beforeunload" : "unload";
|
||||
|
||||
@ -365,7 +365,7 @@ function initializePlatfApplication(applicationImports) {
|
||||
showDebugConsole0();
|
||||
}
|
||||
|
||||
function showDebugConsole() {
|
||||
showDebugConsole = function() {
|
||||
debugConsoleLocalStorageSet(true);
|
||||
showDebugConsole0();
|
||||
}
|
||||
@ -480,6 +480,17 @@ function initializePlatfApplication(applicationImports) {
|
||||
return faviconURL;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Object}
|
||||
*/
|
||||
applicationImports["setResetSettingsCallback"] = function() {
|
||||
return {
|
||||
"call": function(/** function() */ cb) {
|
||||
resetSettings = cb;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -499,4 +510,5 @@ function initializeNoPlatfApplication(applicationImports) {
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "addLogMessage");
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "isShowingDebugConsole");
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "getFaviconURL");
|
||||
setUnsupportedFunc(applicationImports, platfApplicationName, "setResetSettingsCallback");
|
||||
}
|
||||
|
@ -25,6 +25,47 @@ function setCurrentAudioContext(audioContext, audioImports) {
|
||||
return audioContext;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} fileData
|
||||
*/
|
||||
audioImports["initKeepAliveHack"] = function(fileData) {
|
||||
const copiedData = new Uint8Array(fileData.length);
|
||||
copiedData.set(fileData, 0);
|
||||
const copiedDataURI = URL.createObjectURL(new Blob([copiedData], {type: "audio/wav"}));
|
||||
const audioElement = /** @type {HTMLAudioElement} */ (document.createElement("audio"));
|
||||
audioElement.classList.add("_eaglercraftX_keepalive_hack");
|
||||
audioElement.setAttribute("style", "display:none;");
|
||||
audioElement.autoplay = true;
|
||||
audioElement.loop = true;
|
||||
const sourceElement = /** @type {HTMLSourceElement} */ (document.createElement("source"));
|
||||
sourceElement.type = "audio/wav";
|
||||
sourceElement.src = copiedDataURI;
|
||||
audioElement.appendChild(sourceElement);
|
||||
audioElement.addEventListener("seeked", function() {
|
||||
// NOP, wakes up the browser's event loop
|
||||
});
|
||||
parentElement.appendChild(audioElement);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {PannerNode} node
|
||||
* @param {number} maxDist
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} z
|
||||
*/
|
||||
audioImports["setupPanner"] = function(node, maxDist, x, y, z) {
|
||||
node.maxDistance = maxDist;
|
||||
node.rolloffFactor = 1.0;
|
||||
node.panningModel = "HRTF";
|
||||
node.distanceModel = "linear";
|
||||
node.coneInnerAngle = 360.0;
|
||||
node.coneOuterAngle = 0.0;
|
||||
node.coneOuterGain = 0.0;
|
||||
node.setOrientation(0.0, 1.0, 0.0);
|
||||
node.setPosition(x, y, z);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {AudioBufferSourceNode} sourceNode
|
||||
* @param {Object} isEnded
|
||||
@ -72,6 +113,8 @@ function setNoAudioContext(audioImports) {
|
||||
audioImports["getContext"] = function() {
|
||||
return null;
|
||||
};
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "setupPanner");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "initKeepAliveHack");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "registerIsEndedHandler");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "releaseIsEndedHandler");
|
||||
setUnsupportedFunc(audioImports, platfAudioName, "decodeAudioBrowser");
|
||||
|
@ -617,15 +617,19 @@ async function initPlatformInput(inputImports) {
|
||||
/**
|
||||
* @param {number} fpsLimit
|
||||
* @param {number} vsync
|
||||
* @param {number} finish
|
||||
* @return {Promise}
|
||||
*/
|
||||
function updatePlatformAndSleepImpl(fpsLimit, vsync) {
|
||||
function updatePlatformAndSleepImpl(fpsLimit, vsync, finish) {
|
||||
reportWindowSize();
|
||||
if((typeof document.visibilityState !== "string") || (document.visibilityState === "visible")) {
|
||||
if(vsyncSupport && vsync) {
|
||||
manualSyncTimer = 0;
|
||||
return asyncRequestAnimationFrame();
|
||||
}else {
|
||||
if(finish) {
|
||||
webglContext.finish();
|
||||
}
|
||||
if(fpsLimit <= 0) {
|
||||
manualSyncTimer = 0;
|
||||
return swapDelayImpl();
|
||||
|
Reference in New Issue
Block a user