Update #24 - 1000s of optimizations, shared worlds on desktop

This commit is contained in:
lax1dude
2024-03-02 20:51:44 -08:00
parent a50c93cb75
commit 8ab65942c5
624 changed files with 8091 additions and 3620 deletions

View File

@ -73,7 +73,9 @@ public class ChunkUpdateManager {
final CompiledChunk compiledchunk = generator.getCompiledChunk();
if (chunkcompiletaskgenerator$type == ChunkCompileTaskGenerator.Type.REBUILD_CHUNK) {
for (EnumWorldBlockLayer enumworldblocklayer : EnumWorldBlockLayer.values()) {
EnumWorldBlockLayer[] en = EnumWorldBlockLayer._VALUES;
for (int i = 0; i < en.length; ++i) {
EnumWorldBlockLayer enumworldblocklayer = en[i];
if (!compiledchunk.isLayerEmpty(enumworldblocklayer)) {
this.uploadChunk(enumworldblocklayer,
generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(enumworldblocklayer),

View File

@ -0,0 +1,355 @@
package net.lax1dude.eaglercraft.v1_8.minecraft;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.lax1dude.eaglercraft.v1_8.ArrayUtils;
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.minecraft.client.resources.AbstractResourcePack;
/**
* 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 EaglerFolderResourcePack extends AbstractResourcePack {
public static final Logger logger = LogManager.getLogger("EaglerFolderResourcePack");
public static final String SERVER_RESOURCE_PACKS = "srp";
public static final String RESOURCE_PACKS = "resourcepacks";
private final String prefix;
private final String displayName;
private final Set<String> domains;
private final long timestamp;
private static boolean isSupported = false;
public static void setSupported(boolean supported) {
isSupported = supported;
}
public static boolean isSupported() {
return isSupported;
}
public EaglerFolderResourcePack(String resourcePackFileIn, String displayName, String prefix, Set<String> domains, long timestamp) {
super(resourcePackFileIn);
this.displayName = displayName;
this.prefix = prefix;
this.domains = domains;
this.timestamp = timestamp;
}
@Override
public Set<String> getResourceDomains() {
return domains;
}
@Override
protected InputStream getInputStreamByName(String var1) throws IOException {
return (new VFile2(prefix, this.resourcePackFile, var1)).getInputStream();
}
@Override
protected boolean hasResourceName(String var1) {
return (new VFile2(prefix, this.resourcePackFile, var1)).exists();
}
public long getTimestamp() {
return timestamp;
}
public String getDisplayName() {
return displayName;
}
public static List<EaglerFolderResourcePack> getFolderResourcePacks(String prefix) {
if(!isSupported) {
return Collections.emptyList();
}
String str = (new VFile2(prefix, "manifest.json")).getAllChars();
if(str == null) {
return Collections.emptyList();
}
try {
JSONArray json = (new JSONObject(str)).getJSONArray("resourcePacks");
List<EaglerFolderResourcePack> ret = new ArrayList(json.length());
for(int i = 0, l = json.length(); i < l; ++i) {
JSONObject jp = json.getJSONObject(i);
String folderName = jp.getString("folder");
String displayName = jp.optString("name", folderName);
long timestamp = jp.getLong("timestamp");
Set<String> domains = Sets.newHashSet();
JSONArray jsonDomains = jp.getJSONArray("domains");
for(int j = 0, k = jsonDomains.length(); j < k; ++j) {
domains.add(jsonDomains.getString(j));
}
ret.add(new EaglerFolderResourcePack(folderName, displayName, prefix, domains, timestamp));
}
return ret;
}catch(JSONException ex) {
logger.error("Failed to load resource pack manifest!");
logger.error(ex);
return Collections.emptyList();
}
}
public static EaglerFolderResourcePack importResourcePack(String name, String prefix, byte[] file) throws IOException {
if(!isSupported) {
return null;
}
logger.info("Importing resource pack: {}", name);
int idx = name.lastIndexOf('.');
if(idx != -1) {
name = name.substring(0, idx);
}
String folderName = name.replaceAll("[^A-Za-z0-9\\-_ \\(\\)]", "_");
final List<EaglerFolderResourcePack> existingLst = getFolderResourcePacks(RESOURCE_PACKS);
vigg: for(;;) {
for(int i = 0, l = existingLst.size(); i < l; ++i) {
EaglerFolderResourcePack rp = existingLst.get(i);
if(rp.resourcePackFile.equalsIgnoreCase(folderName)) {
folderName = folderName + "-";
continue vigg;
}
}
break;
}
List<String> fileNames = Lists.newArrayList();
logger.info("Counting files...");
ZipInputStream ziss = new ZipInputStream(new EaglerInputStream(file));
ZipEntry zipEntry;
while ((zipEntry = ziss.getNextEntry()) != null) {
if (!zipEntry.isDirectory()) {
fileNames.add(zipEntry.getName());
}
}
int prefixLen = Integer.MAX_VALUE;
for(int i = 0, l = fileNames.size(); i < l; ++i) {
String fn = fileNames.get(i);
if(fn.equals("pack.mcmeta") || fn.endsWith("/pack.mcmeta")) {
int currPrefixLen = fn.length() - 11;
if (prefixLen > currPrefixLen) {
prefixLen = currPrefixLen;
}
}
}
if (prefixLen == Integer.MAX_VALUE) {
prefixLen = 0;
}
Set<String> domainsList = Sets.newHashSet();
String fn;
for(int i = 0, l = fileNames.size(); i < l; ++i) {
fn = fileNames.get(i);
if(fn.length() > prefixLen + 7) {
fn = fn.substring(prefixLen + 7);
int j = fn.indexOf('/');
if(j != -1) {
domainsList.add(fn.substring(0, j));
}
}
}
VFile2 dstDir = new VFile2(prefix, folderName);
logger.info("Extracting to: {}", dstDir.getPath());
try {
int totalSize = 0;
int totalFiles = 0;
int lastProg = 0;
ziss = new ZipInputStream(new EaglerInputStream(file));
while ((zipEntry = ziss.getNextEntry()) != null) {
if (!zipEntry.isDirectory()) {
fn = zipEntry.getName();
if(fn.length() > prefixLen) {
byte[] buffer = new byte[(int)zipEntry.getSize()];
int i = 0, j;
while(i < buffer.length && (j = ziss.read(buffer, i, buffer.length - i)) != -1) {
i += j;
}
(new VFile2(prefix, folderName, fn.substring(prefixLen))).setAllBytes(buffer);
totalSize += buffer.length;
++totalFiles;
if(totalSize - lastProg > 25000) {
lastProg = totalSize;
logger.info("Extracted {} files, {} bytes from ZIP file...", totalFiles, totalSize);
}
}
}
}
}catch(IOException ex) {
logger.error("Encountered an error extracting zip file, deleting extracted files...");
for(int i = 0, l = fileNames.size(); i < l; ++i) {
fn = fileNames.get(i);
if(fn.length() > prefixLen) {
(new VFile2(dstDir, fn.substring(prefixLen))).delete();
}
}
throw ex;
}
logger.info("Updating manifest...");
VFile2 manifestFile = new VFile2(prefix, "manifest.json");
String str = manifestFile.getAllChars();
JSONArray arr = null;
if(str != null) {
try {
arr = (new JSONObject(str)).getJSONArray("resourcePacks");
}catch(JSONException ex) {
}
}
if(arr == null) {
arr = new JSONArray();
}
JSONObject manifestEntry = new JSONObject();
manifestEntry.put("folder", folderName);
manifestEntry.put("name", name);
long timestamp = System.currentTimeMillis();
manifestEntry.put("timestamp", timestamp);
JSONArray domainsListJson = new JSONArray();
for(String str2 : domainsList) {
domainsListJson.put(str2);
}
manifestEntry.put("domains", domainsListJson);
arr.put(manifestEntry);
manifestFile.setAllChars((new JSONObject()).put("resourcePacks", arr).toString());
logger.info("Done!");
return new EaglerFolderResourcePack(folderName, name, prefix, domainsList, timestamp);
}
public static void loadRemoteResourcePack(String url, String hash, Consumer<EaglerFolderResourcePack> cb, Consumer<Runnable> ast, Runnable loading) {
if (!isSupported || !hash.matches("^[a-f0-9]{40}$")) {
cb.accept(null);
return;
}
final List<EaglerFolderResourcePack> lst = getFolderResourcePacks(SERVER_RESOURCE_PACKS);
for(int i = 0, l = lst.size(); i < l; ++i) {
EaglerFolderResourcePack rp = lst.get(i);
if(rp.resourcePackFile.equals(hash)) {
cb.accept(rp);
return;
}
}
PlatformRuntime.downloadRemoteURIByteArray(url, arr -> {
ast.accept(() -> {
if (arr == null) {
cb.accept(null);
return;
}
SHA1Digest digest = new SHA1Digest();
digest.update(arr, 0, arr.length);
byte[] hashOut = new byte[20];
digest.doFinal(hashOut, 0);
if(!hash.equals(ArrayUtils.hexString(hashOut))) {
logger.error("Downloaded resource pack hash does not equal expected resource pack hash!");
cb.accept(null);
return;
}
if(lst.size() >= 5) {
lst.sort(Comparator.comparingLong(pack -> pack.timestamp));
for(int i = 0; i < lst.size() - 5; i++) {
deleteResourcePack(SERVER_RESOURCE_PACKS, lst.get(i).resourcePackFile);
}
}
loading.run();
try {
cb.accept(importResourcePack(hash, SERVER_RESOURCE_PACKS, arr));
}catch(IOException ex) {
logger.error("Failed to load resource pack downloaded from server!");
logger.error(ex);
cb.accept(null);
}
});
});
}
public static void deleteResourcePack(EaglerFolderResourcePack pack) {
deleteResourcePack(pack.prefix, pack.resourcePackFile);
}
public static void deleteResourcePack(String prefix, String name) {
if (!isSupported) {
return;
}
logger.info("Deleting resource pack: {}/{}", prefix, name);
(new VFile2(prefix, name)).listFiles(true).forEach(VFile2::delete);
VFile2 manifestFile = new VFile2(prefix, "manifest.json");
String str = manifestFile.getAllChars();
if(str != null) {
try {
JSONArray json = (new JSONObject(str)).getJSONArray("resourcePacks");
boolean changed = false;
for(int i = 0, l = json.length(); i < l; ++i) {
if(json.getJSONObject(i).getString("folder").equals(name)) {
json.remove(i);
changed = true;
break;
}
}
if(changed) {
manifestFile.setAllChars((new JSONObject()).put("resourcePacks", json).toString());
}else {
logger.warn("Failed to remove pack \"{}\" from manifest, it wasn't found in the list for some reason", name);
}
}catch(JSONException ex) {
}
}
}
public static void deleteOldResourcePacks(String prefix, long maxAge) {
if (!isSupported) {
return;
}
long millis = System.currentTimeMillis();
List<EaglerFolderResourcePack> lst = getFolderResourcePacks(prefix);
for(int i = 0, l = lst.size(); i < l; ++i) {
EaglerFolderResourcePack rp = lst.get(i);
if(millis - rp.timestamp > maxAge) {
deleteResourcePack(rp);
}
}
}
}

View File

@ -273,7 +273,8 @@ public class EaglerTextureAtlasSprite {
public String call() throws Exception {
StringBuilder stringbuilder = new StringBuilder();
for (int[] aint1 : aint) {
for (int j = 0; j < aint.length; ++j) {
int[] aint1 = aint[j];
if (stringbuilder.length() > 0) {
stringbuilder.append(", ");
}

View File

@ -0,0 +1,52 @@
package net.lax1dude.eaglercraft.v1_8.minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* 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 GuiScreenGenericErrorMessage extends GuiScreen {
private String str1;
private String str2;
private GuiScreen cont;
public GuiScreenGenericErrorMessage(String str1, String str2, GuiScreen cont) {
this.str1 = I18n.format(str1);
this.str2 = I18n.format(str2);
this.cont = cont;
}
public void initGui() {
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("gui.done")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(fontRendererObj, str1, this.width / 2, 70, 11184810);
this.drawCenteredString(fontRendererObj, str2, this.width / 2, 90, 16777215);
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(cont);
}
}
}