Update #45 - Fixed various issues with the client

This commit is contained in:
lax1dude
2024-12-14 20:54:34 -08:00
parent 12535d429f
commit 346047cf24
39 changed files with 571 additions and 208 deletions

View File

@ -19,7 +19,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
*/
public class Display {
private static long lastSwap = 0l;
private static long lastDPIUpdate = -250l;
private static float cacheDPI = 1.0f;
@ -79,41 +78,6 @@ public class Display {
PlatformInput.update(limitFramerate);
}
private static final long[] defaultSyncPtr = new long[1];
public static void sync(int limitFramerate) {
sync(limitFramerate, defaultSyncPtr);
}
public static boolean sync(int limitFramerate, long[] timerPtr) {
boolean limitFPS = limitFramerate > 0 && limitFramerate < 1000;
boolean blocked = false;
if(limitFPS) {
if(timerPtr[0] == 0l) {
timerPtr[0] = EagRuntime.steadyTimeMillis();
}else {
long millis = EagRuntime.steadyTimeMillis();
long frameMillis = (1000l / limitFramerate);
long frameTime = millis - timerPtr[0];
if(frameTime > 2000l || frameTime < 0l) {
frameTime = frameMillis;
timerPtr[0] = millis;
}else {
timerPtr[0] += frameMillis;
}
if(frameTime >= 0l && frameTime < frameMillis) {
EagUtils.sleep(frameMillis - frameTime);
blocked = true;
}
}
}else {
timerPtr[0] = 0l;
}
return blocked;
}
public static boolean contextLost() {
return PlatformInput.contextLost();
}

View File

@ -375,4 +375,8 @@ public class EagRuntime {
PlatformRuntime.immediateContinue();
}
public static boolean immediateContinueSupported() {
return PlatformRuntime.immediateContinueSupported();
}
}

View File

@ -142,6 +142,16 @@ public class EaglerInputStream extends InputStream {
}
}
public static byte[] inputStreamToBytesNoClose(InputStream is) throws IOException {
EaglerOutputStream os = new EaglerOutputStream(1024);
byte[] buf = new byte[1024];
int i;
while ((i = is.read(buf)) != -1) {
os.write(buf, 0, i);
}
return os.toByteArray();
}
public byte[] getAsArray() {
if (pos == 0 && count == buf.length) {
return buf;

View File

@ -10,7 +10,7 @@ public class EaglercraftVersion {
/// Customize these to fit your fork:
public static final String projectForkName = "EaglercraftX";
public static final String projectForkVersion = "u44";
public static final String projectForkVersion = "u45";
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 = "u44";
public static final String projectOriginVersion = "u45";
public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace
// EPK Version Identifier
public static final String EPKVersionIdentifier = "u44"; // Set to null to disable EPK version check
public static final String EPKVersionIdentifier = "u45"; // 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 = 44;
public static final int updateBundlePackageVersionInt = 45;
public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName;

View File

@ -211,7 +211,7 @@ public class EaglerFolderResourcePack extends AbstractResourcePack {
i += j;
}
}else {
buffer = EaglerInputStream.inputStreamToBytes(ziss);
buffer = EaglerInputStream.inputStreamToBytesNoClose(ziss);
}
(new VFile2(prefix, folderName, fn.substring(prefixLen))).setAllBytes(buffer);
totalSize += buffer.length;

View File

@ -930,6 +930,8 @@ public class EaglercraftGPU {
InstancedParticleRenderer.destroy();
EffectPipelineFXAA.destroy();
TextureCopyUtil.destroy();
FixedFunctionPipeline.flushCache();
StreamBuffer.destroyPool();
emulatedVAOs = false;
emulatedVAOState = null;
glesVers = -1;

View File

@ -76,8 +76,8 @@ public class FixedFunctionPipeline {
StreamBufferInstance sb = self.streamBuffer.getBuffer(buffer.remaining());
self.currentVertexArray = sb;
EaglercraftGPU.bindGLBufferArray(sb.vertexArray);
EaglercraftGPU.bindGLArrayBuffer(sb.vertexBuffer);
EaglercraftGPU.bindGLBufferArray(sb.getVertexArray());
EaglercraftGPU.bindGLArrayBuffer(sb.getVertexBuffer());
_wglBufferSubData(GL_ARRAY_BUFFER, 0, buffer);

View File

@ -7,7 +7,7 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
/**
* Copyright (c) 2023 lax1dude. All Rights Reserved.
* Copyright (c) 2023-2024 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
@ -23,10 +23,48 @@ import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
*/
public class StreamBuffer {
public static final int poolSize = 16;
public final int initialSize;
public final int initialCount;
public final int maxCount;
protected static final PoolInstance[] pool = new PoolInstance[poolSize];
protected static int poolBufferID = 0;
static {
for(int i = 0; i < poolSize; ++i) {
pool[i] = new PoolInstance();
}
}
protected static class PoolInstance {
protected IBufferGL vertexBuffer = null;
protected int vertexBufferSize = 0;
}
private static PoolInstance fillPoolInstance() {
PoolInstance ret = pool[poolBufferID++];
if(poolBufferID > poolSize - 1) {
poolBufferID = 0;
}
return ret;
}
private static void resizeInstance(PoolInstance instance, int requiredMemory) {
if(instance.vertexBuffer == null) {
instance.vertexBuffer = _wglGenBuffers();
}
if(instance.vertexBufferSize < requiredMemory) {
int newSize = (requiredMemory & 0xFFFFF000) + 0x2000;
EaglercraftGPU.bindGLArrayBuffer(instance.vertexBuffer);
_wglBufferData(GL_ARRAY_BUFFER, newSize, GL_STREAM_DRAW);
instance.vertexBufferSize = newSize;
}
}
protected StreamBufferInstance[] buffers;
protected int currentBufferId = 0;
@ -36,9 +74,8 @@ public class StreamBuffer {
public static class StreamBufferInstance {
protected PoolInstance poolInstance = null;
protected IBufferArrayGL vertexArray = null;
protected IBufferGL vertexBuffer = null;
protected int vertexBufferSize = 0;
public boolean bindQuad16 = false;
public boolean bindQuad32 = false;
@ -48,7 +85,7 @@ public class StreamBuffer {
}
public IBufferGL getVertexBuffer() {
return vertexBuffer;
return poolInstance.vertexBuffer;
}
}
@ -58,9 +95,14 @@ public class StreamBuffer {
}
public StreamBuffer(int initialSize, int initialCount, int maxCount, IStreamBufferInitializer initializer) {
if(maxCount > poolSize) {
maxCount = poolSize;
}
this.buffers = new StreamBufferInstance[initialCount];
for(int i = 0; i < this.buffers.length; ++i) {
this.buffers[i] = new StreamBufferInstance();
StreamBufferInstance j = new StreamBufferInstance();
j.poolInstance = fillPoolInstance();
this.buffers[i] = j;
}
this.initialSize = initialSize;
this.initialCount = initialCount;
@ -70,18 +112,10 @@ public class StreamBuffer {
public StreamBufferInstance getBuffer(int requiredMemory) {
StreamBufferInstance next = buffers[(currentBufferId++) % buffers.length];
if(next.vertexBuffer == null) {
next.vertexBuffer = _wglGenBuffers();
}
resizeInstance(next.poolInstance, requiredMemory);
if(next.vertexArray == null) {
next.vertexArray = EaglercraftGPU.createGLBufferArray();
initializer.initialize(next.vertexArray, next.vertexBuffer);
}
if(next.vertexBufferSize < requiredMemory) {
int newSize = (requiredMemory & 0xFFFFF000) + 0x2000;
EaglercraftGPU.bindGLArrayBuffer(next.vertexBuffer);
_wglBufferData(GL_ARRAY_BUFFER, newSize, GL_STREAM_DRAW);
next.vertexBufferSize = newSize;
initializer.initialize(next.vertexArray, next.poolInstance.vertexBuffer);
}
return next;
}
@ -102,12 +136,10 @@ public class StreamBuffer {
if(buffers[i].vertexArray != null) {
EaglercraftGPU.destroyGLBufferArray(buffers[i].vertexArray);
}
if(buffers[i].vertexBuffer != null) {
_wglDeleteBuffers(buffers[i].vertexBuffer);
}
}
}
buffers = newArray;
refill();
}
overflowCounter = 0;
}else if(overflowCounter > 15) {
@ -125,25 +157,51 @@ public class StreamBuffer {
}
}
buffers = newArray;
refill();
}
overflowCounter = 0;
}
currentBufferId = 0;
}
private void refill() {
for(int i = 0; i < buffers.length; ++i) {
PoolInstance j = fillPoolInstance();
StreamBufferInstance k = buffers[i];
if(j != k.poolInstance) {
PoolInstance l = k.poolInstance;
k.poolInstance = j;
if(k.vertexArray != null) {
if(j.vertexBuffer == null) {
resizeInstance(j, l.vertexBufferSize);
}
initializer.initialize(k.vertexArray, j.vertexBuffer);
}
}
}
}
public void destroy() {
for(int i = 0; i < buffers.length; ++i) {
StreamBufferInstance next = buffers[i];
if(next.vertexArray != null) {
EaglercraftGPU.destroyGLBufferArray(next.vertexArray);
}
if(next.vertexBuffer != null) {
_wglDeleteBuffers(next.vertexBuffer);
}
}
buffers = new StreamBufferInstance[initialCount];
for(int i = 0; i < buffers.length; ++i) {
buffers[i] = new StreamBufferInstance();
for(int i = 0; i < initialCount; ++i) {
StreamBufferInstance j = new StreamBufferInstance();
j.poolInstance = fillPoolInstance();
buffers[i] = j;
}
}
public static void destroyPool() {
for(int i = 0; i < pool.length; ++i) {
if(pool[i].vertexBuffer != null) {
_wglDeleteBuffers(pool[i].vertexBuffer);
pool[i].vertexBuffer = null;
}
}
}

View File

@ -153,7 +153,7 @@ public class SingleplayerServerController implements ISaveFormat {
}
public static boolean isChannelNameAllowed(String ch) {
return !IPC_CHANNEL.equals(ch) && !PLAYER_CHANNEL.equals(ch);
return !ch.startsWith("~!");
}
public static void openPlayerChannel(String ch) {

View File

@ -1,5 +1,6 @@
package net.lax1dude.eaglercraft.v1_8.sp.lan;
import java.util.LinkedList;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
@ -42,6 +43,8 @@ class LANClientPeer {
protected long startTime;
protected String localICECandidate = null;
protected boolean localChannel = false;
protected List<byte[]> packetPreBuffer = null;
protected LANClientPeer(String clientId) {
this.clientId = clientId;
@ -75,7 +78,19 @@ class LANClientPeer {
protected void handleSuccess() {
if(state == SENT_ICE_CANDIDATE) {
state = RECEIVED_SUCCESS;
if(localChannel) {
SingleplayerServerController.openPlayerChannel(clientId);
PlatformWebRTC.serverLANPeerMapIPC(clientId, clientId);
if(packetPreBuffer != null) {
for(byte[] b : packetPreBuffer) {
ClientPlatformSingleplayer.sendPacket(new IPCPacketData(clientId, b));
}
packetPreBuffer = null;
}
state = CONNECTED;
}else {
state = RECEIVED_SUCCESS;
}
}else if(state != CONNECTED) {
logger.error("Relay [{}] unexpected IPacket05ClientSuccess for '{}'", LANServerController.lanRelaySocket.getURI(), clientId);
}
@ -113,13 +128,7 @@ class LANClientPeer {
localICECandidate = ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates;
continue read_loop;
}
}
case RECEIVED_ICE_CANDIDATE: {
if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
LANServerController.lanRelaySocket.writePacket(new RelayPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates));
state = SENT_ICE_CANDIDATE;
continue read_loop;
}
break;
}
case RECEIVED_DESCRIPTION: {
if(evt instanceof LANPeerEvent.LANPeerDescriptionEvent) {
@ -127,15 +136,50 @@ class LANClientPeer {
state = SENT_DESCRIPTION;
continue read_loop;
}
break;
}
case RECEIVED_ICE_CANDIDATE: {
if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
LANServerController.lanRelaySocket.writePacket(new RelayPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates));
state = SENT_ICE_CANDIDATE;
continue read_loop;
}else if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) {
localChannel = true;
continue read_loop;
}else if(evt instanceof LANPeerEvent.LANPeerPacketEvent) {
if(packetPreBuffer == null) packetPreBuffer = new LinkedList<>();
packetPreBuffer.add(((LANPeerEvent.LANPeerPacketEvent)evt).payload);
continue read_loop;
}
break;
}
case SENT_ICE_CANDIDATE: {
if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) {
localChannel = true;
continue read_loop;
}else if(evt instanceof LANPeerEvent.LANPeerPacketEvent) {
if(packetPreBuffer == null) packetPreBuffer = new LinkedList<>();
packetPreBuffer.add(((LANPeerEvent.LANPeerPacketEvent)evt).payload);
continue read_loop;
}
break;
}
case SENT_ICE_CANDIDATE:
case RECEIVED_SUCCESS: {
if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) {
SingleplayerServerController.openPlayerChannel(clientId);
PlatformWebRTC.serverLANPeerMapIPC(clientId, clientId);
if(packetPreBuffer != null) {
for(byte[] b : packetPreBuffer) {
ClientPlatformSingleplayer.sendPacket(new IPCPacketData(clientId, b));
}
packetPreBuffer = null;
}
state = CONNECTED;
continue read_loop;
}else if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
continue read_loop;
}
break;
}
case CONNECTED: {
if(evt instanceof LANPeerEvent.LANPeerPacketEvent) {
@ -144,6 +188,7 @@ class LANClientPeer {
ClientPlatformSingleplayer.sendPacket(new IPCPacketData(clientId, ((LANPeerEvent.LANPeerPacketEvent)evt).payload));
continue read_loop;
}
break;
}
default: {
break;

View File

@ -12,6 +12,7 @@ import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.*;
@ -142,7 +143,9 @@ public class LANServerController {
while((pkt = lanRelaySocket.readPacket()) != null) {
if(pkt instanceof RelayPacket02NewClient) {
RelayPacket02NewClient ipkt = (RelayPacket02NewClient) pkt;
if(clients.containsKey(ipkt.clientId)) {
if(!SingleplayerServerController.isChannelNameAllowed(ipkt.clientId)) {
logger.error("Relay [{}] relay tried to open disallowed channel name: '{}'", lanRelaySocket.getURI(), ipkt.clientId);
}else if(clients.containsKey(ipkt.clientId)) {
logger.error("Relay [{}] relay provided duplicate client '{}'", lanRelaySocket.getURI(), ipkt.clientId);
}else {
clients.put(ipkt.clientId, new LANClientPeer(ipkt.clientId));

View File

@ -103,11 +103,10 @@ public class WorldConverterEPK {
public static byte[] exportWorld(String worldName) {
String realWorldName = worldName;
String worldOwner = "UNKNOWN";
String splitter = new String(new char[] { (char)253, (char)233, (char)233 });
if(worldName.contains(splitter)) {
int i = worldName.lastIndexOf(splitter);
worldOwner = worldName.substring(i + 3);
realWorldName = worldName.substring(0, i);
int j = worldName.lastIndexOf(new String(new char[] { (char)253, (char)233, (char)233 }));
if(j != -1) {
worldOwner = worldName.substring(j + 3);
realWorldName = worldName.substring(0, j);
}
VFile2 worldDir = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(realWorldName, false).getWorldDirectory();
logger.info("Exporting world directory \"{}\" as EPK", worldDir.getPath());

View File

@ -70,7 +70,6 @@ public class WorldConverterMCA {
ZipEntry f = null;
int lastProgUpdate = 0;
int prog = 0;
byte[] bb = new byte[16384];
while ((f = zis.getNextEntry()) != null) {
if (f.getName().contains("__MACOSX/")) continue;
if (f.isDirectory()) continue;
@ -85,7 +84,7 @@ public class WorldConverterMCA {
j += k;
}
}else {
b = EaglerInputStream.inputStreamToBytes(zis);
b = EaglerInputStream.inputStreamToBytesNoClose(zis);
}
String fileName = f.getName().substring(folderPrefixOffset);
if (fileName.equals("level.dat") || fileName.equals("level.dat_old")) {