Update #30 - Fixed various client bugs
This commit is contained in:
parent
32fda35ace
commit
c6ac781036
31
README.md
31
README.md
|
@ -153,6 +153,37 @@ The default eaglercraftXOpts values is this:
|
|||
- `enableSignatureBadge:` show a badge on the title screen indicating if digital signature is valid
|
||||
- `checkRelaysForUpdates:` proprietary feature used in offline downloads
|
||||
- `allowVoiceClient:` can be used to disable the voice chat feature
|
||||
- `allowFNAWSkins:` can be used to disable the high poly FNAW skins
|
||||
- `localStorageNamespace:` can be used to change the prefix of the local storage keys (Default: `"_eaglercraftX"`)
|
||||
- `hooks:` can be used to define JavaScript callbacks for certain events
|
||||
* `localStorageSaved:` JavaScript callback to save local storage keys
|
||||
* `localStorageLoaded:` JavaScript callback to load local storage keys
|
||||
|
||||
### Using Hooks
|
||||
|
||||
You may want to implement some custom logic for loading/saving certain local storage keys. The eaglercraftXOpts hooks section can be used to override the client's local storage load and save functions. Currently, local storage keys are used to save game settings, the user's profile, custom servers, and shared world relays. Worlds and resource packs do not use local storage keys because modern browsers limit local storage keys to only 5 megabytes per domain which is too small for saving entire worlds and resource packs. Worlds and resource packs are saved using [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).
|
||||
|
||||
window.eaglercraftXOpts = {
|
||||
...
|
||||
...
|
||||
...
|
||||
hooks: {
|
||||
localStorageSaved: function(key, data) {
|
||||
// 'key' is local storage key name as a string
|
||||
// 'data' is base64-encoded byte array as a string
|
||||
// function returns nothing
|
||||
},
|
||||
localStorageLoaded: function(key) {
|
||||
// 'key' is local storage key name as a string
|
||||
// function returns a base64-encoded byte array as a string
|
||||
// function returns null if the key does not exist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Be aware that the client will still save the key to the browser's local storage anyway even if you define a custom save handler, and will just attempt to load the key from the browser's local storage normally if you return null, these are meant to be used like event handlers for creating backups of keys instead of completely replacing the local storage save and load functions.
|
||||
|
||||
On a normal client you will only ever need to handle local storage keys called `_eaglercraftX.p` (profile), `_eaglercraftX.g` (game settings), `_eaglercraftX.s` (server list), `_eaglercraftX.r` (shared world relays), feel free to just ignore any other keys. It is guaranteed that the data the client stores will always be valid base64, so it is best practice to decode it to raw binary first if possible to reduce it's size before saving it to something like a MySQL database in your backend if you are trying to implement some kind of profile syncing system for your website. The keys already have GZIP compression applied to them by default so don't bother trying to compress them yourself a second time because it won't reduce their size.
|
||||
|
||||
## Developing a Client
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
u29
|
||||
u30
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
> DELETE 1 @ 1 : 4
|
||||
|
||||
> CHANGE 1 : 55 @ 1 : 4
|
||||
> CHANGE 1 : 56 @ 1 : 4
|
||||
|
||||
~
|
||||
~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
|
@ -31,6 +31,7 @@
|
|||
~
|
||||
~ import net.lax1dude.eaglercraft.v1_8.Display;
|
||||
~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
~ import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
~ import net.lax1dude.eaglercraft.v1_8.EaglerXBungeeVersion;
|
||||
~ import net.lax1dude.eaglercraft.v1_8.HString;
|
||||
~ import net.lax1dude.eaglercraft.v1_8.IOUtils;
|
||||
|
@ -430,7 +431,21 @@
|
|||
|
||||
~ Util.func_181617_a((FutureTask) this.scheduledTasks.remove(0), logger);
|
||||
|
||||
> DELETE 18 @ 18 : 26
|
||||
> CHANGE 7 : 18 @ 7 : 8
|
||||
|
||||
~ if (this.timer.elapsedTicks > 1) {
|
||||
~ long watchdog = System.currentTimeMillis();
|
||||
~ for (int j = 0; j < this.timer.elapsedTicks; ++j) {
|
||||
~ this.runTick();
|
||||
~ long millis = System.currentTimeMillis();
|
||||
~ if (millis - watchdog > 50l) {
|
||||
~ watchdog = millis;
|
||||
~ EagUtils.sleep(0l);
|
||||
~ }
|
||||
~ }
|
||||
~ } else if (this.timer.elapsedTicks == 1) {
|
||||
|
||||
> DELETE 10 @ 10 : 18
|
||||
|
||||
> CHANGE 1 : 4 @ 1 : 5
|
||||
|
||||
|
@ -503,9 +518,13 @@
|
|||
|
||||
+ Mouse.tickCursorShape();
|
||||
|
||||
> INSERT 5 : 6 @ 5
|
||||
> INSERT 5 : 10 @ 5
|
||||
|
||||
+ if (Display.isVSyncSupported()) {
|
||||
+ Display.setVSync(this.gameSettings.enableVsync);
|
||||
+ } else {
|
||||
+ this.gameSettings.enableVsync = false;
|
||||
+ }
|
||||
|
||||
> DELETE 34 @ 34 : 52
|
||||
|
||||
|
|
|
@ -30,7 +30,9 @@
|
|||
|
||||
> DELETE 7 @ 7 : 11
|
||||
|
||||
> DELETE 3 @ 3 : 18
|
||||
> CHANGE 3 : 4 @ 3 : 18
|
||||
|
||||
~ private static final Logger tipLogger = LogManager.getLogger("EaglercraftX");
|
||||
|
||||
> CHANGE 3 : 4 @ 3 : 4
|
||||
|
||||
|
@ -44,7 +46,14 @@
|
|||
|
||||
~ for (Entry entry : (Set<Entry>) map.entrySet()) {
|
||||
|
||||
> INSERT 14 : 24 @ 14
|
||||
> INSERT 12 : 16 @ 12
|
||||
|
||||
+ if (this.sndRegistry.getObject(new ResourceLocation("minecraft:sounds/music/game/calm1.ogg")) == null) {
|
||||
+ tipLogger.info(
|
||||
+ "Download this resource pack if you want music: https://bafybeiayojww5jfyzvlmtuk7l5ufkt7nlfto7mhwmzf2vs4bvsjd5ouiuq.ipfs.nftstorage.link/?filename=Music_For_Eaglercraft.zip");
|
||||
+ }
|
||||
|
||||
> INSERT 2 : 12 @ 2
|
||||
|
||||
+ public static class SoundMap {
|
||||
+
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
|
||||
> DELETE 2 @ 2 : 3
|
||||
|
||||
> INSERT 1 : 9 @ 1
|
||||
> INSERT 1 : 10 @ 1
|
||||
|
||||
+
|
||||
+ import com.google.common.collect.Maps;
|
||||
+
|
||||
+ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
+ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
+ import net.lax1dude.eaglercraft.v1_8.opengl.OpenGlHelper;
|
||||
+ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
|
||||
|
@ -32,12 +33,16 @@
|
|||
|
||||
+ private RenderPlayer eaglerRenderer;
|
||||
|
||||
> CHANGE 82 : 88 @ 82 : 83
|
||||
> CHANGE 82 : 92 @ 82 : 83
|
||||
|
||||
~ this.skinMap.put("slim", new RenderPlayer(this, true, false));
|
||||
~ this.skinMap.put("zombie", new RenderPlayer(this, false, true));
|
||||
~ if (EagRuntime.getConfiguration().isAllowFNAWSkins()) {
|
||||
~ this.eaglerRenderer = new RenderHighPoly(this, this.playerRenderer.getMainModel(),
|
||||
~ this.playerRenderer.shadowSize);
|
||||
~ } else {
|
||||
~ this.eaglerRenderer = this.playerRenderer;
|
||||
~ }
|
||||
~ this.skinMap.put("eagler",
|
||||
~ Minecraft.getMinecraft().gameSettings.enableFNAWSkins ? this.eaglerRenderer : this.playerRenderer);
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@
|
|||
|
||||
~ worldIn.theItemInWorldManager.initializeGameType(parWorld.getWorldInfo().getGameType());
|
||||
~ } else {
|
||||
~ parEntityPlayerMP2.theItemInWorldManager.setGameType(lanGamemode);
|
||||
~ worldIn.theItemInWorldManager.setGameType(lanGamemode);
|
||||
~ }
|
||||
|
||||
> CHANGE 7 : 8 @ 7 : 8
|
||||
|
|
|
@ -66,6 +66,10 @@ public class PlatformApplication {
|
|||
}
|
||||
|
||||
public static void setLocalStorage(String name, byte[] data) {
|
||||
setLocalStorage(name, data, true);
|
||||
}
|
||||
|
||||
public static void setLocalStorage(String name, byte[] data, boolean hooks) {
|
||||
if(data == null) {
|
||||
(new File("_eagstorage."+name+".dat")).delete();
|
||||
}else {
|
||||
|
@ -78,6 +82,10 @@ public class PlatformApplication {
|
|||
}
|
||||
|
||||
public static byte[] getLocalStorage(String data) {
|
||||
return getLocalStorage(data, true);
|
||||
}
|
||||
|
||||
public static byte[] getLocalStorage(String data, boolean hooks) {
|
||||
File f = new File("_eagstorage."+data+".dat");
|
||||
if(!f.isFile()) {
|
||||
return null;
|
||||
|
|
|
@ -230,6 +230,10 @@ public class PlatformInput {
|
|||
glfwSwapBuffers(win);
|
||||
}
|
||||
|
||||
public static boolean isVSyncSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean wasResized() {
|
||||
boolean b = windowResized;
|
||||
windowResized = false;
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.json.JSONObject;
|
|||
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapterHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayEntry;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +32,8 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
|
|||
|
||||
public final List<DefaultServer> defaultServers = new ArrayList();
|
||||
|
||||
private final DesktopClientConfigAdapterHooks hooks = new DesktopClientConfigAdapterHooks();
|
||||
|
||||
@Override
|
||||
public String getDefaultLocale() {
|
||||
return "en_US";
|
||||
|
@ -129,4 +132,32 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowFNAWSkins() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalStorageNamespace() {
|
||||
return EaglercraftVersion.localStorageNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
}
|
||||
|
||||
private static class DesktopClientConfigAdapterHooks implements IClientConfigAdapterHooks {
|
||||
|
||||
@Override
|
||||
public void callLocalStorageSavedHook(String key, String base64) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String callLocalStorageLoadHook(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,10 @@ public class Display {
|
|||
PlatformInput.setVSync(enable);
|
||||
}
|
||||
|
||||
public static boolean isVSyncSupported() {
|
||||
return PlatformInput.isVSyncSupported();
|
||||
}
|
||||
|
||||
public static void update() {
|
||||
PlatformInput.update();
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ public class EaglercraftVersion {
|
|||
/// Customize these to fit your fork:
|
||||
|
||||
public static final String projectForkName = "EaglercraftX";
|
||||
public static final String projectForkVersion = "u29";
|
||||
public static final String projectForkVersion = "u30";
|
||||
public static final String projectForkVendor = "lax1dude";
|
||||
|
||||
public static final String projectForkURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8";
|
||||
|
@ -20,7 +20,7 @@ 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 = "u29";
|
||||
public static final String projectOriginVersion = "u30";
|
||||
|
||||
public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace
|
||||
|
||||
|
@ -31,7 +31,7 @@ public class EaglercraftVersion {
|
|||
public static final boolean enableUpdateService = true;
|
||||
|
||||
public static final String updateBundlePackageName = "net.lax1dude.eaglercraft.v1_8.client";
|
||||
public static final int updateBundlePackageVersionInt = 29;
|
||||
public static final int updateBundlePackageVersionInt = 30;
|
||||
|
||||
public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName;
|
||||
|
||||
|
@ -60,4 +60,6 @@ public class EaglercraftVersion {
|
|||
|
||||
public static final boolean forceDemoMode = false;
|
||||
|
||||
public static final String localStorageNamespace = "_eaglercraftX";
|
||||
|
||||
}
|
||||
|
|
|
@ -69,4 +69,11 @@ public interface IClientConfigAdapter {
|
|||
boolean isEnableSignatureBadge();
|
||||
|
||||
boolean isAllowVoiceClient();
|
||||
|
||||
boolean isAllowFNAWSkins();
|
||||
|
||||
String getLocalStorageNamespace();
|
||||
|
||||
IClientConfigAdapterHooks getHooks();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
package net.lax1dude.eaglercraft.v1_8.internal.teavm.opts;
|
||||
|
||||
import org.teavm.jso.JSIndexer;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
|
@ -19,12 +15,10 @@ import org.teavm.jso.JSProperty;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface JSEaglercraftXOptsRelaysArray extends JSObject {
|
||||
public interface IClientConfigAdapterHooks {
|
||||
|
||||
@JSIndexer
|
||||
JSEaglercraftXOptsRelay get(int idx);
|
||||
void callLocalStorageSavedHook(String key, String base64);
|
||||
|
||||
@JSProperty
|
||||
int getLength();
|
||||
String callLocalStorageLoadHook(String key);
|
||||
|
||||
}
|
|
@ -13,6 +13,21 @@ import net.minecraft.client.resources.IResourceManager;
|
|||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2023 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.
|
||||
*
|
||||
*/
|
||||
public class BlockVertexIDs implements IResourceManagerReloadListener {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("BlockVertexIDsCSV");
|
||||
|
|
|
@ -61,7 +61,7 @@ public class EaglerSkinTexture implements ITextureObject {
|
|||
}
|
||||
System.arraycopy(pixels, 0, this.pixels, 0, pixels.length);
|
||||
if(textureId != -1) {
|
||||
TextureUtil.uploadTextureImageAllocate(textureId, new ImageData(width, height, pixels, true), false, false);
|
||||
TextureUtil.uploadTextureImageSub(textureId, new ImageData(width, height, pixels, true), 0, 0, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,14 +73,20 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
}
|
||||
|
||||
private void updateOptions() {
|
||||
DefaultSkins[] arr = DefaultSkins.defaultSkinsMap;
|
||||
if(!EagRuntime.getConfiguration().isAllowFNAWSkins()) {
|
||||
DefaultSkins[] arrNoFNAW = new DefaultSkins[arr.length - 5];
|
||||
System.arraycopy(arr, 0, arrNoFNAW, 0, arrNoFNAW.length);
|
||||
arr = arrNoFNAW;
|
||||
}
|
||||
int numCustom = EaglerProfile.customSkins.size();
|
||||
String[] n = new String[numCustom + DefaultSkins.defaultSkinsMap.length];
|
||||
String[] n = new String[numCustom + arr.length];
|
||||
for(int i = 0; i < numCustom; ++i) {
|
||||
n[i] = EaglerProfile.customSkins.get(i).name;
|
||||
}
|
||||
int numDefault = DefaultSkins.defaultSkinsMap.length;
|
||||
int numDefault = arr.length;
|
||||
for(int j = 0; j < numDefault; ++j) {
|
||||
n[numCustom + j] = DefaultSkins.defaultSkinsMap[j].name;
|
||||
n[numCustom + j] = arr[j].name;
|
||||
}
|
||||
dropDownOptions = n;
|
||||
}
|
||||
|
@ -106,6 +112,10 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
GlStateManager.translate(skinX + 2, skinY - 9, 0.0f);
|
||||
GlStateManager.scale(0.75f, 0.75f, 0.75f);
|
||||
|
||||
if(selectedSlot > dropDownOptions.length - 1) {
|
||||
selectedSlot = 0;
|
||||
}
|
||||
|
||||
int numberOfCustomSkins = EaglerProfile.customSkins.size();
|
||||
int skid = selectedSlot - numberOfCustomSkins;
|
||||
SkinModel selectedSkinModel = skid < 0 ? EaglerProfile.customSkins.get(selectedSlot).model : DefaultSkins.getSkinFromId(skid).model;
|
||||
|
|
|
@ -56,11 +56,15 @@ public class GuiScreenImportExportProfile extends GuiScreen {
|
|||
FileChooserResult result = EagRuntime.getFileChooserResult();
|
||||
if(result != null) {
|
||||
mc.loadingScreen.eaglerShow(I18n.format("settingsBackup.importing.1"), "settingsBackup.importing.2");
|
||||
try {
|
||||
ProfileImporter importer = new ProfileImporter(result.fileData);
|
||||
try {
|
||||
importer.readHeader();
|
||||
mc.displayGuiScreen(new GuiScreenImportProfile(importer, back));
|
||||
}catch(IOException ex) {
|
||||
try {
|
||||
importer.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
EagRuntime.debugPrintStackTrace(ex);
|
||||
mc.displayGuiScreen(new GuiScreenGenericErrorMessage("settingsBackup.importing.failed.1", "settingsBackup.importing.failed.2", back));
|
||||
}
|
||||
|
|
|
@ -62,6 +62,14 @@ public class GuiScreenImportProfile extends GuiScreen {
|
|||
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 140, I18n.format("gui.cancel")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
try {
|
||||
importer.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
if(!doImportProfile && !doImportSettings && !doImportServers && !doImportResourcePacks) {
|
||||
|
|
|
@ -69,8 +69,8 @@ public class ProfileExporter {
|
|||
osb.write(new byte[]{(byte)255,(byte)255,(byte)255,(byte)255}); // this will be replaced with the file count
|
||||
|
||||
osb.write('G');
|
||||
OutputStream os = EaglerZLIB.newGZIPOutputStream(osb);
|
||||
|
||||
int fileCount = 2;
|
||||
try(OutputStream os = EaglerZLIB.newGZIPOutputStream(osb)) {
|
||||
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
|
||||
os.write(new byte[]{(byte)9,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)116,(byte)121,
|
||||
(byte)112,(byte)101}); // 9 + file-type
|
||||
|
@ -84,7 +84,6 @@ public class ProfileExporter {
|
|||
os.write((doExportProfile ? 1 : 0) | (doExportSettings ? 2 : 0) | (doExportServers ? 4 : 0) | (doExportResourcePacks ? 8 : 0));
|
||||
os.write('>');
|
||||
|
||||
int fileCount = 2;
|
||||
|
||||
if(doExportProfile) {
|
||||
byte[] profileData = EaglerProfile.write();
|
||||
|
@ -159,7 +158,7 @@ public class ProfileExporter {
|
|||
}
|
||||
|
||||
os.write(new byte[]{(byte)69,(byte)78,(byte)68,(byte)36}); // END$
|
||||
os.close();
|
||||
}
|
||||
|
||||
osb.write(new byte[]{(byte)58,(byte)58,(byte)58,(byte)89,(byte)69,(byte)69,(byte)58,(byte)62}); // :::YEE:>
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.lax1dude.eaglercraft.v1_8.profile;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
|
@ -29,7 +30,7 @@ import net.minecraft.client.multiplayer.ServerList;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class ProfileImporter {
|
||||
public class ProfileImporter implements Closeable {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("ProfileImporter");
|
||||
|
||||
|
@ -148,4 +149,9 @@ public class ProfileImporter {
|
|||
}
|
||||
logger.info("Import complete!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
epkDecompiler.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -468,4 +468,13 @@ public class RenderHighPoly extends RenderPlayer {
|
|||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
public void renderLivingAt(AbstractClientPlayer abstractclientplayer, double d0, double d1, double d2) {
|
||||
if (abstractclientplayer.isEntityAlive() && abstractclientplayer.isPlayerSleeping()) {
|
||||
super.renderLivingAt(abstractclientplayer, d0 - (double) abstractclientplayer.renderOffsetX,
|
||||
d1 - (double) abstractclientplayer.renderOffsetY, d2 - (double) abstractclientplayer.renderOffsetZ);
|
||||
} else {
|
||||
super.renderLivingAt(abstractclientplayer, d0, d1, d2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public enum SkinModel {
|
|||
private SkinModel(int id, HighPolySkin highPoly) {
|
||||
this.id = id;
|
||||
this.width = 256;
|
||||
this.height = 128;
|
||||
this.height = 256;
|
||||
this.profileSkinType = "eagler";
|
||||
this.sanitize = true;
|
||||
this.highPoly = highPoly;
|
||||
|
|
|
@ -156,7 +156,6 @@ public class GuiShareToLan extends GuiScreen {
|
|||
this.mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(I18n.format("lanServer.opened")
|
||||
.replace("$relay$", LANServerController.getCurrentURI()).replace("$code$", code)));
|
||||
} else {
|
||||
SingleplayerServerController.configureLAN(mc.theWorld.getWorldInfo().getGameType(), false);
|
||||
this.mc.displayGuiScreen(new GuiScreenNoRelays(this, "noRelay.titleFail"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -340,9 +340,11 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
|
|||
}
|
||||
EaglerInputStream bi = new EaglerInputStream(fullData);
|
||||
int i = (bi.read() << 24) | (bi.read() << 16) | (bi.read() << 8) | bi.read();
|
||||
InputStream inflaterInputStream = EaglerZLIB.newInflaterInputStream(bi);
|
||||
fullData = new byte[i];
|
||||
int r = IOUtils.readFully(inflaterInputStream, fullData);
|
||||
int r;
|
||||
try(InputStream inflaterInputStream = EaglerZLIB.newInflaterInputStream(bi)) {
|
||||
r = IOUtils.readFully(inflaterInputStream, fullData);
|
||||
}
|
||||
if (i != r) {
|
||||
logger.warn("Decompressed packet expected size {} differs from actual size {}!", i, r);
|
||||
}
|
||||
|
|
|
@ -479,7 +479,7 @@ public class EaglerIntegratedServerWorker {
|
|||
|
||||
while(true) {
|
||||
mainLoop();
|
||||
EagUtils.sleep(1l);
|
||||
EagUtils.sleep(0l);
|
||||
}
|
||||
}catch(Throwable tt) {
|
||||
if(tt instanceof ReportedException) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.lax1dude.eaglercraft.v1_8.sp.server.export;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
@ -24,7 +25,7 @@ import net.lax1dude.eaglercraft.v1_8.IOUtils;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class EPKDecompiler {
|
||||
public class EPKDecompiler implements Closeable {
|
||||
|
||||
public static class FileEntry {
|
||||
public final String type;
|
||||
|
@ -178,4 +179,9 @@ public class EPKDecompiler {
|
|||
return new String(charIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
zis.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class WorldConverterEPK {
|
|||
folderName += "_";
|
||||
worldDir = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
|
||||
}
|
||||
EPKDecompiler dc = new EPKDecompiler(archiveContents);
|
||||
try(EPKDecompiler dc = new EPKDecompiler(archiveContents)) {
|
||||
EPKDecompiler.FileEntry f = null;
|
||||
int lastProgUpdate = 0;
|
||||
int prog = 0;
|
||||
|
@ -81,6 +81,7 @@ public class WorldConverterEPK {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info("EPK was successfully extracted into directory \"{}\"", worldDir.getPath());
|
||||
String[] worldsTxt = EaglerSaveFormat.worldsList.getAllLines();
|
||||
if(worldsTxt == null || worldsTxt.length <= 0 || (worldsTxt.length == 1 && worldsTxt[0].trim().length() <= 0)) {
|
||||
|
|
|
@ -50,9 +50,9 @@ public class WorldConverterMCA {
|
|||
folderName += "_";
|
||||
worldDir = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
|
||||
}
|
||||
ZipInputStream zis = new ZipInputStream(new EaglerInputStream(archiveContents));
|
||||
ZipEntry folderNameFile = null;
|
||||
List<char[]> fileNames = new ArrayList<>();
|
||||
try(ZipInputStream zis = new ZipInputStream(new EaglerInputStream(archiveContents))) {
|
||||
ZipEntry folderNameFile = null;
|
||||
while((folderNameFile = zis.getNextEntry()) != null) {
|
||||
if (folderNameFile.getName().contains("__MACOSX/")) continue;
|
||||
if (folderNameFile.isDirectory()) continue;
|
||||
|
@ -60,10 +60,11 @@ public class WorldConverterMCA {
|
|||
if (!(lowerName.endsWith(".dat") || lowerName.endsWith(".dat_old") || lowerName.endsWith(".mca") || lowerName.endsWith(".mcr"))) continue;
|
||||
fileNames.add(folderNameFile.getName().toCharArray());
|
||||
}
|
||||
}
|
||||
final int[] i = new int[] { 0 };
|
||||
while(fileNames.get(0).length > i[0] && fileNames.stream().allMatch(w -> w[i[0]] == fileNames.get(0)[i[0]])) i[0]++;
|
||||
int folderPrefixOffset = i[0];
|
||||
zis = new ZipInputStream(new EaglerInputStream(archiveContents));
|
||||
try(ZipInputStream zis = new ZipInputStream(new EaglerInputStream(archiveContents))) {
|
||||
ZipEntry f = null;
|
||||
int lastProgUpdate = 0;
|
||||
int prog = 0;
|
||||
|
@ -157,6 +158,7 @@ public class WorldConverterMCA {
|
|||
EaglerIntegratedServerWorker.sendProgress("singleplayer.busy.importing.2", prog);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info("MCA was successfully extracted into directory \"{}\"", worldDir.getPath());
|
||||
String[] worldsTxt = EaglerSaveFormat.worldsList.getAllLines();
|
||||
if(worldsTxt == null || worldsTxt.length <= 0 || (worldsTxt.length == 1 && worldsTxt[0].trim().length() <= 0)) {
|
||||
|
@ -172,9 +174,10 @@ public class WorldConverterMCA {
|
|||
|
||||
public static byte[] exportWorld(String folderName) throws IOException {
|
||||
EaglerOutputStream bao = new EaglerOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bao);
|
||||
VFile2 worldFolder;
|
||||
try(ZipOutputStream zos = new ZipOutputStream(bao)) {
|
||||
zos.setComment("contains backup of world '" + folderName + "'");
|
||||
VFile2 worldFolder = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
|
||||
worldFolder = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
|
||||
logger.info("Exporting world directory \"{}\" as MCA", worldFolder.getPath());
|
||||
VFile2 vf = new VFile2(worldFolder, "level.dat");
|
||||
byte[] b;
|
||||
|
@ -294,7 +297,7 @@ public class WorldConverterMCA {
|
|||
EaglerIntegratedServerWorker.sendProgress("singleplayer.busy.exporting.2", prog);
|
||||
}
|
||||
}
|
||||
zos.close();
|
||||
}
|
||||
logger.info("World directory \"{}\" was successfully exported as MCA", worldFolder.getPath());
|
||||
return bao.toByteArray();
|
||||
}
|
||||
|
|
|
@ -243,9 +243,9 @@ public class IntegratedServerPlayerNetworkManager {
|
|||
temporaryOutputStream.write((len >> 16) & 0xFF);
|
||||
temporaryOutputStream.write((len >> 8) & 0xFF);
|
||||
temporaryOutputStream.write(len & 0xFF);
|
||||
OutputStream os = EaglerZLIB.newDeflaterOutputStream(temporaryOutputStream);
|
||||
try(OutputStream os = EaglerZLIB.newDeflaterOutputStream(temporaryOutputStream)) {
|
||||
temporaryBuffer.readBytes(os, len);
|
||||
os.close();
|
||||
}
|
||||
compressedData = temporaryOutputStream.toByteArray();
|
||||
}catch(IOException ex) {
|
||||
logger.error("Failed to compress packet {}!", pkt.getClass().getSimpleName());
|
||||
|
|
|
@ -64,7 +64,7 @@ public class RelayUpdateChecker {
|
|||
for(net.lax1dude.eaglercraft.v1_8.sp.relay.RelayEntry etr : EagRuntime.getConfiguration().getRelays()) {
|
||||
relaysList.add(new RelayEntry(etr.address));
|
||||
}
|
||||
byte[] b = PlatformApplication.getLocalStorage("lastRelayUpdate");
|
||||
byte[] b = PlatformApplication.getLocalStorage("lastRelayUpdate", false);
|
||||
if(b != null) {
|
||||
try {
|
||||
lastUpdateCheck = (new DataInputStream(new EaglerInputStream(b))).readLong();
|
||||
|
@ -79,7 +79,7 @@ public class RelayUpdateChecker {
|
|||
try {
|
||||
EaglerOutputStream bao = new EaglerOutputStream(8);
|
||||
(new DataOutputStream(bao)).writeLong(lastUpdateCheck);
|
||||
PlatformApplication.setLocalStorage("lastRelayUpdate", bao.toByteArray());
|
||||
PlatformApplication.setLocalStorage("lastRelayUpdate", bao.toByteArray(), false);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
for (int i = 0, l = relaysList.size(); i < l; ++i) {
|
||||
|
|
|
@ -148,7 +148,16 @@ public class UpdateCertificate {
|
|||
throw new CertificateInvalidException("SHA256 checksum of signature payload is invalid!");
|
||||
}
|
||||
|
||||
return new UpdateCertificate(certData, EaglerZLIB.newGZIPInputStream(new EaglerInputStream(signaturePayload)), vers);
|
||||
UpdateCertificate cert;
|
||||
try(InputStream gis = EaglerZLIB.newGZIPInputStream(new EaglerInputStream(signaturePayload))) {
|
||||
cert = new UpdateCertificate(certData, gis, vers);
|
||||
}
|
||||
|
||||
if(System.currentTimeMillis() < cert.sigTimestamp) {
|
||||
throw new CertificateInvalidException("Update certificate timestamp is from the future!?");
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
private UpdateCertificate(byte[] certData, InputStream is, int sigVers) throws IOException {
|
||||
|
|
|
@ -94,7 +94,7 @@ public class UpdateService {
|
|||
}
|
||||
}
|
||||
}
|
||||
byte[] latestUpdate = PlatformApplication.getLocalStorage(EaglercraftVersion.updateLatestLocalStorageKey);
|
||||
byte[] latestUpdate = PlatformApplication.getLocalStorage(EaglercraftVersion.updateLatestLocalStorageKey, false);
|
||||
if(latestUpdate != null) {
|
||||
addCertificateToSet(latestUpdate, false);
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ public class UpdateService {
|
|||
latestUpdateFound = cert;
|
||||
if (saveLatest) {
|
||||
PlatformApplication.setLocalStorage(EaglercraftVersion.updateLatestLocalStorageKey,
|
||||
certificateData);
|
||||
certificateData, false);
|
||||
}
|
||||
}
|
||||
}else if(EagRuntime.getConfiguration().isLogInvalidCerts()) {
|
||||
|
|
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.
Binary file not shown.
|
@ -95,24 +95,53 @@ public class PlatformApplication {
|
|||
private static native void setClipboard0(String str);
|
||||
|
||||
public static void setLocalStorage(String name, byte[] data) {
|
||||
setLocalStorage(name, data, true);
|
||||
}
|
||||
|
||||
public static void setLocalStorage(String name, byte[] data, boolean hooks) {
|
||||
IClientConfigAdapter adapter = PlatformRuntime.getClientConfigAdapter();
|
||||
String eagName = adapter.getLocalStorageNamespace() + "." + name;
|
||||
String b64 = Base64.encodeBase64String(data);
|
||||
try {
|
||||
Storage s = Window.current().getLocalStorage();
|
||||
if(s != null) {
|
||||
if(data != null) {
|
||||
s.setItem("_eaglercraftX." + name, Base64.encodeBase64String(data));
|
||||
s.setItem(eagName, b64);
|
||||
}else {
|
||||
s.removeItem("_eaglercraftX." + name);
|
||||
s.removeItem(eagName);
|
||||
}
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
if(hooks) {
|
||||
adapter.getHooks().callLocalStorageSavedHook(name, b64);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] getLocalStorage(String name) {
|
||||
return getLocalStorage(name, true);
|
||||
}
|
||||
|
||||
public static byte[] getLocalStorage(String name, boolean hooks) {
|
||||
IClientConfigAdapter adapter = PlatformRuntime.getClientConfigAdapter();
|
||||
String eagName = adapter.getLocalStorageNamespace() + "." + name;
|
||||
byte[] hooked = null;
|
||||
if(hooks) {
|
||||
String hookedStr = adapter.getHooks().callLocalStorageLoadHook(eagName);
|
||||
if(hookedStr != null) {
|
||||
try {
|
||||
hooked = Base64.decodeBase64(hookedStr);
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("Invalid Base64 recieved from local storage hook!");
|
||||
hooked = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(hooked == null) {
|
||||
try {
|
||||
Storage s = Window.current().getLocalStorage();
|
||||
if(s != null) {
|
||||
String str = s.getItem("_eaglercraftX." + name);
|
||||
String str = s.getItem(eagName);
|
||||
if(str != null) {
|
||||
return Base64.decodeBase64(str);
|
||||
}else {
|
||||
|
@ -124,6 +153,9 @@ public class PlatformApplication {
|
|||
}catch(Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
return hooked;
|
||||
}
|
||||
}
|
||||
|
||||
private static final DateFormat dateFormatSS = EagRuntime.fixDateFormat(new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"));
|
||||
|
|
|
@ -30,16 +30,18 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
|||
import net.minecraft.util.MathHelper;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 LAX1DUDE. All Rights Reserved.
|
||||
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
public class PlatformAudio {
|
||||
|
|
|
@ -104,6 +104,7 @@ public class PlatformInput {
|
|||
public static boolean lockKeys = false;
|
||||
|
||||
private static boolean vsync = true;
|
||||
private static boolean vsyncSupport = false;
|
||||
|
||||
@JSBody(params = { }, script = "window.onbeforeunload = () => {return false;};")
|
||||
private static native void onBeforeCloseRegister();
|
||||
|
@ -252,7 +253,18 @@ public class PlatformInput {
|
|||
mouseDY = 0.0D;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
onBeforeCloseRegister();
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
|
||||
try {
|
||||
asyncRequestAnimationFrame();
|
||||
vsyncSupport = true;
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("VSync is not supported on this browser!");
|
||||
}
|
||||
|
||||
fullscreenQuery = fullscreenMediaQuery();
|
||||
if (keyboardLockSupported = checkKeyboardLockSupported()) {
|
||||
|
@ -300,6 +312,9 @@ public class PlatformInput {
|
|||
vsync = enable;
|
||||
}
|
||||
|
||||
@JSBody(params = { "doc" }, script = "return (doc.visibilityState === \"visible\");")
|
||||
private static native boolean getVisibilityState(JSObject doc);
|
||||
|
||||
public static void update() {
|
||||
double r = win.getDevicePixelRatio();
|
||||
int w = PlatformRuntime.parent.getClientWidth();
|
||||
|
@ -320,11 +335,15 @@ public class PlatformInput {
|
|||
PlatformRuntime.lastFrame = t;
|
||||
}
|
||||
}
|
||||
if(vsync) {
|
||||
if(getVisibilityState(win.getDocument())) {
|
||||
if(vsyncSupport && vsync) {
|
||||
asyncRequestAnimationFrame();
|
||||
}else {
|
||||
EagUtils.sleep(0l);
|
||||
}
|
||||
}else {
|
||||
EagUtils.sleep(50l);
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
|
@ -348,6 +367,10 @@ public class PlatformInput {
|
|||
}, 50);
|
||||
}
|
||||
|
||||
public static boolean isVSyncSupported() {
|
||||
return vsyncSupport;
|
||||
}
|
||||
|
||||
static void initFramebuffer(WebGL2RenderingContext ctx, WebGLFramebuffer fbo, int sw, int sh) {
|
||||
context = ctx;
|
||||
mainFramebuffer = fbo;
|
||||
|
@ -599,7 +622,7 @@ public class PlatformInput {
|
|||
keyEvents.clear();
|
||||
}
|
||||
|
||||
@JSBody(params = {}, script = "return window.matchMedia('(display-mode: fullscreen)');")
|
||||
@JSBody(params = {}, script = "return window.matchMedia(\"(display-mode: fullscreen)\");")
|
||||
private static native JSObject fullscreenMediaQuery();
|
||||
|
||||
@JSBody(params = { "mediaQuery" }, script = "return mediaQuery.matches;")
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.teavm.jso.JSBody;
|
|||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
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.HTMLCanvasElement;
|
||||
|
@ -21,7 +22,6 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
|||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsAssetsURI;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsAssetsURIsArray;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsRoot;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.ILogRedirector;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
|
@ -87,7 +87,7 @@ public class ClientMain {
|
|||
if(epkSingleURL != null) {
|
||||
configEPKFiles = new EPKFileEntry[] { new EPKFileEntry(epkSingleURL, "") };
|
||||
}else {
|
||||
JSEaglercraftXOptsAssetsURIsArray epkURLs = eaglercraftOpts.getAssetsURIArray();
|
||||
JSArrayReader<JSEaglercraftXOptsAssetsURI> epkURLs = eaglercraftOpts.getAssetsURIArray();
|
||||
int len = epkURLs.getLength();
|
||||
if(len == 0) {
|
||||
throw new JSONException("assetsURI array cannot be empty!");
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.teavm.jso.dom.html.HTMLDocument;
|
|||
import org.teavm.jso.dom.html.HTMLElement;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
|
||||
/**
|
||||
|
@ -63,13 +64,13 @@ public class DebugConsoleWindow {
|
|||
destroyWindow();
|
||||
}
|
||||
});
|
||||
if("true".equals(parent.getLocalStorage().getItem("_eaglercraftX.showDebugConsole"))) {
|
||||
if("true".equals(parent.getLocalStorage().getItem(PlatformRuntime.getClientConfigAdapter().getLocalStorageNamespace() + ".showDebugConsole"))) {
|
||||
showDebugConsole0();
|
||||
}
|
||||
}
|
||||
|
||||
public static void showDebugConsole() {
|
||||
parent.getLocalStorage().setItem("_eaglercraftX.showDebugConsole", "true");
|
||||
parent.getLocalStorage().setItem(PlatformRuntime.getClientConfigAdapter().getLocalStorageNamespace() + ".showDebugConsole", "true");
|
||||
showDebugConsole0();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,14 @@ import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
|
|||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.core.JSArrayReader;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapterHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsRelay;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsRelaysArray;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsRoot;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsServer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsServersArray;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayEntry;
|
||||
|
||||
/**
|
||||
|
@ -56,6 +57,9 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
|||
private boolean checkRelaysForUpdates = false;
|
||||
private boolean enableSignatureBadge = false;
|
||||
private boolean allowVoiceClient = true;
|
||||
private boolean allowFNAWSkins = true;
|
||||
private String localStorageNamespace = "_eaglercraftX";
|
||||
private final TeaVMClientConfigAdapterHooks hooks = new TeaVMClientConfigAdapterHooks();
|
||||
|
||||
public void loadNative(JSObject jsObject) {
|
||||
integratedServerOpts = new JSONObject();
|
||||
|
@ -75,6 +79,12 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
|||
logInvalidCerts = EaglercraftVersion.enableUpdateService && !demoMode && eaglercraftXOpts.getLogInvalidCerts(false);
|
||||
enableSignatureBadge = eaglercraftXOpts.getEnableSignatureBadge(false);
|
||||
allowVoiceClient = eaglercraftXOpts.getAllowVoiceClient(true);
|
||||
allowFNAWSkins = eaglercraftXOpts.getAllowFNAWSkins(true);
|
||||
localStorageNamespace = eaglercraftXOpts.getLocalStorageNamespace(EaglercraftVersion.localStorageNamespace);
|
||||
JSEaglercraftXOptsHooks hooksObj = eaglercraftXOpts.getHooks();
|
||||
if(hooksObj != null) {
|
||||
hooks.loadHooks(hooksObj);
|
||||
}
|
||||
|
||||
integratedServerOpts.put("worldsDB", worldsDB);
|
||||
integratedServerOpts.put("demoMode", demoMode);
|
||||
|
@ -82,8 +92,9 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
|||
integratedServerOpts.put("allowUpdateSvc", isAllowUpdateSvc);
|
||||
integratedServerOpts.put("allowUpdateDL", isAllowUpdateDL);
|
||||
integratedServerOpts.put("allowVoiceClient", allowVoiceClient);
|
||||
integratedServerOpts.put("allowFNAWSkins", allowFNAWSkins);
|
||||
|
||||
JSEaglercraftXOptsServersArray serversArray = eaglercraftXOpts.getServers();
|
||||
JSArrayReader<JSEaglercraftXOptsServer> serversArray = eaglercraftXOpts.getServers();
|
||||
if(serversArray != null) {
|
||||
for(int i = 0, l = serversArray.getLength(); i < l; ++i) {
|
||||
JSEaglercraftXOptsServer serverEntry = serversArray.get(i);
|
||||
|
@ -95,7 +106,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
JSEaglercraftXOptsRelaysArray relaysArray = eaglercraftXOpts.getRelays();
|
||||
JSArrayReader<JSEaglercraftXOptsRelay> relaysArray = eaglercraftXOpts.getRelays();
|
||||
if(relaysArray != null) {
|
||||
boolean gotAPrimary = false;
|
||||
for(int i = 0, l = relaysArray.getLength(); i < l; ++i) {
|
||||
|
@ -162,6 +173,8 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
|||
logInvalidCerts = EaglercraftVersion.enableUpdateService && !demoMode && eaglercraftOpts.optBoolean("logInvalidCerts", false);
|
||||
enableSignatureBadge = eaglercraftOpts.optBoolean("enableSignatureBadge", false);
|
||||
allowVoiceClient = eaglercraftOpts.optBoolean("allowVoiceClient", true);
|
||||
allowFNAWSkins = eaglercraftOpts.optBoolean("allowFNAWSkins", true);
|
||||
localStorageNamespace = eaglercraftOpts.optString("localStorageNamespace", EaglercraftVersion.localStorageNamespace);
|
||||
JSONArray serversArray = eaglercraftOpts.optJSONArray("servers");
|
||||
if(serversArray != null) {
|
||||
for(int i = 0, l = serversArray.length(); i < l; ++i) {
|
||||
|
@ -309,6 +322,21 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
|||
return allowVoiceClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowFNAWSkins() {
|
||||
return allowFNAWSkins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalStorageNamespace() {
|
||||
return localStorageNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
|
@ -327,6 +355,8 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
|||
jsonObject.put("checkRelaysForUpdates", checkRelaysForUpdates);
|
||||
jsonObject.put("enableSignatureBadge", enableSignatureBadge);
|
||||
jsonObject.put("allowVoiceClient", allowVoiceClient);
|
||||
jsonObject.put("allowFNAWSkins", allowFNAWSkins);
|
||||
jsonObject.put("localStorageNamespace", localStorageNamespace);
|
||||
JSONArray serversArr = new JSONArray();
|
||||
for(int i = 0, l = defaultServers.size(); i < l; ++i) {
|
||||
DefaultServer srv = defaultServers.get(i);
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.browser.Window;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapterHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsHooks;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
public class TeaVMClientConfigAdapterHooks implements IClientConfigAdapterHooks {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("TeaVMClientConfigAdapterHooks");
|
||||
|
||||
private LocalStorageSaveHook saveHook = null;
|
||||
private LocalStorageLoadHook loadHook = null;
|
||||
|
||||
@JSFunctor
|
||||
private static interface LocalStorageSaveHook extends JSObject {
|
||||
void call(String key, String base64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLocalStorageSavedHook(String key, String base64) {
|
||||
if(saveHook != null) {
|
||||
callHookSafe("localStorageSaved", () -> {
|
||||
saveHook.call(key, base64);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface LocalStorageLoadHook extends JSObject {
|
||||
String call(String key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String callLocalStorageLoadHook(String key) {
|
||||
if(loadHook != null) {
|
||||
return (String)callHookSafeWithReturn("localStorageLoaded", () -> {
|
||||
return loadHook.call(key);
|
||||
});
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void callHookSafe(String identifer, Runnable hooker) {
|
||||
Window.setTimeout(() -> {
|
||||
try {
|
||||
hooker.run();
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception while invoking eaglercraftXOpts \"{}\" hook!", identifer);
|
||||
logger.error(t);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@Async
|
||||
private static native Object callHookSafeWithReturn(String identifer, Supplier<Object> hooker);
|
||||
|
||||
private static void callHookSafeWithReturn(String identifer, Supplier<Object> hooker, final AsyncCallback<Object> cb) {
|
||||
Window.setTimeout(() -> {
|
||||
Object res = null;
|
||||
try {
|
||||
res = hooker.get();
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception while invoking eaglercraftXOpts \"{}\" hook!", identifer);
|
||||
logger.error(t);
|
||||
}finally {
|
||||
cb.complete(res);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public void loadHooks(JSEaglercraftXOptsHooks hooks) {
|
||||
saveHook = (LocalStorageSaveHook)hooks.getLocalStorageSavedHook();
|
||||
loadHook = (LocalStorageLoadHook)hooks.getLocalStorageLoadedHook();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
package net.lax1dude.eaglercraft.v1_8.internal.teavm.opts;
|
||||
|
||||
import org.teavm.jso.JSIndexer;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
|
@ -19,12 +18,12 @@ import org.teavm.jso.JSProperty;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface JSEaglercraftXOptsAssetsURIsArray extends JSObject {
|
||||
public abstract class JSEaglercraftXOptsHooks implements JSObject {
|
||||
|
||||
@JSIndexer
|
||||
JSEaglercraftXOptsAssetsURI get(int idx);
|
||||
@JSBody(script = "return (typeof this.localStorageSaved === \"function\") ? this.localStorageSaved : null;")
|
||||
public native JSObject getLocalStorageSavedHook();
|
||||
|
||||
@JSProperty
|
||||
int getLength();
|
||||
@JSBody(script = "return (typeof this.localStorageLoaded === \"function\") ? this.localStorageLoaded : null;")
|
||||
public native JSObject getLocalStorageLoadedHook();
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.teavm.opts;
|
|||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.core.JSArrayReader;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
|
@ -27,7 +28,7 @@ public abstract class JSEaglercraftXOptsRoot implements JSObject {
|
|||
public native String getAssetsURI();
|
||||
|
||||
@JSBody(script = "return (typeof this.assetsURI === \"object\") ? this.assetsURI : null;")
|
||||
public native JSEaglercraftXOptsAssetsURIsArray getAssetsURIArray();
|
||||
public native JSArrayReader<JSEaglercraftXOptsAssetsURI> getAssetsURIArray();
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.lang === \"string\") ? this.lang : def;")
|
||||
public native String getLang(String defaultValue);
|
||||
|
@ -48,10 +49,10 @@ public abstract class JSEaglercraftXOptsRoot implements JSObject {
|
|||
public native boolean getDemoMode(boolean defaultValue);
|
||||
|
||||
@JSBody(script = "return (typeof this.servers === \"object\") ? this.servers : null;")
|
||||
public native JSEaglercraftXOptsServersArray getServers();
|
||||
public native JSArrayReader<JSEaglercraftXOptsServer> getServers();
|
||||
|
||||
@JSBody(script = "return (typeof this.relays === \"object\") ? this.relays : null;")
|
||||
public native JSEaglercraftXOptsRelaysArray getRelays();
|
||||
public native JSArrayReader<JSEaglercraftXOptsRelay> getRelays();
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.checkShaderGLErrors === \"boolean\") ? this.checkShaderGLErrors : def;")
|
||||
public native boolean getCheckShaderGLErrors(boolean defaultValue);
|
||||
|
@ -83,4 +84,13 @@ public abstract class JSEaglercraftXOptsRoot implements JSObject {
|
|||
@JSBody(params = { "def" }, script = "return (typeof this.allowVoiceClient === \"boolean\") ? this.allowVoiceClient : def;")
|
||||
public native boolean getAllowVoiceClient(boolean defaultValue);
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.allowFNAWSkins === \"boolean\") ? this.allowFNAWSkins : def;")
|
||||
public native boolean getAllowFNAWSkins(boolean defaultValue);
|
||||
|
||||
@JSBody(script = "return (typeof this.hooks === \"object\") ? this.hooks : null;")
|
||||
public native JSEaglercraftXOptsHooks getHooks();
|
||||
|
||||
@JSBody(params = { "def" }, script = "return (typeof this.localStorageNamespace === \"string\") ? this.localStorageNamespace : def;")
|
||||
public native String getLocalStorageNamespace(String defaultValue);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package net.lax1dude.eaglercraft.v1_8.internal.teavm.opts;
|
||||
|
||||
import org.teavm.jso.JSIndexer;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
/**
|
||||
* Copyright (c) 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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
public interface JSEaglercraftXOptsServersArray extends JSObject {
|
||||
|
||||
@JSIndexer
|
||||
JSEaglercraftXOptsServer get(int idx);
|
||||
|
||||
@JSProperty
|
||||
int getLength();
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user