Various mixin/injector additions

This commit is contained in:
Lucas
2019-06-08 11:58:34 +02:00
parent ffcb7b8b45
commit 2c38de7061
37 changed files with 852 additions and 158 deletions

View File

@@ -87,7 +87,7 @@ public class RuneLite
public static final File PROFILES_DIR = new File(RUNELITE_DIR, "profiles");
public static final File PLUGIN_DIR = new File(RUNELITE_DIR, "plugins");
public static final File SCREENSHOT_DIR = new File(RUNELITE_DIR, "screenshots");
static final RuneLiteSplashScreen splashScreen = new RuneLiteSplashScreen();
private static final RuneLiteSplashScreen splashScreen = new RuneLiteSplashScreen();
@Getter

View File

@@ -709,7 +709,7 @@ public class MenuManager
}
/**
* Adds to the map of swaps - Pre-baked Abstract entry
* Adds to the map of swaps - Pre-baked entry
*/
public void addSwap(ComparableEntry swapFrom, ComparableEntry swapTo)
{

View File

@@ -120,8 +120,10 @@ public class ChatFilterPlugin extends Plugin
}
MessageNode messageNode = (MessageNode) client.getMessages().get(messageId);
String name = messageNode.getName();
if (!shouldFilterPlayerMessage(name))
if (client.getLocalPlayer().getName().equals(messageNode.getName()) ||
!config.filterFriends() && messageNode.isFromFriend() ||
!config.filterClan() && messageNode.isFromClanMate())
{
return;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 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 OWNER 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.runelite.client.plugins.inventorygrid;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("inventorygrid")
public interface InventoryGridConfig extends Config
{
@ConfigItem(
keyName = "showItem",
name = "Show item",
description = "Show a preview of the item in the new slot"
)
default boolean showItem()
{
return true;
}
@ConfigItem(
keyName = "showGrid",
name = "Show grid",
description = "Show a grid on the inventory while dragging"
)
default boolean showGrid()
{
return true;
}
@ConfigItem(
keyName = "showHighlight",
name = "Highlight background",
description = "Show a green background highlight on the new slot"
)
default boolean showHighlight()
{
return true;
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek>
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 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 OWNER 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.runelite.client.plugins.inventorygrid;
import com.google.inject.Inject;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import net.runelite.api.Client;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
class InventoryGridOverlay extends Overlay
{
private static final int INVENTORY_SIZE = 28;
private static final int DRAG_DELAY = 5;
private static final Color HIGHLIGHT = new Color(0, 255, 0, 45);
private static final Color GRID = new Color(255, 255, 255, 45);
private final InventoryGridConfig config;
private final Client client;
private final ItemManager itemManager;
@Inject
private InventoryGridOverlay(InventoryGridConfig config, Client client, ItemManager itemManager)
{
this.itemManager = itemManager;
this.client = client;
this.config = config;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
}
@Override
public Dimension render(Graphics2D graphics)
{
final Widget if1DraggingWidget = client.getIf1DraggedWidget();
final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY);
if (if1DraggingWidget == null || if1DraggingWidget != inventoryWidget
|| client.getItemPressedDuration() < DRAG_DELAY)
{
return null;
}
final net.runelite.api.Point mouse = client.getMouseCanvasPosition();
final Point mousePoint = new Point(mouse.getX(), mouse.getY());
for (int i = 0; i < INVENTORY_SIZE; ++i)
{
WidgetItem widgetItem = inventoryWidget.getWidgetItem(i);
final Rectangle bounds = widgetItem.getCanvasBounds();
boolean inBounds = bounds.contains(mousePoint);
if (config.showItem() && inBounds)
{
final WidgetItem draggedItem = inventoryWidget.getWidgetItem(client.getIf1DraggedItemIndex());
final BufferedImage draggedItemImage = itemManager.getImage(draggedItem.getId());
final int x = (int) bounds.getX();
final int y = (int) bounds.getY();
graphics.setComposite(AlphaComposite.SrcOver.derive(0.3f));
graphics.drawImage(draggedItemImage, x, y, null);
graphics.setComposite(AlphaComposite.SrcOver);
}
if (config.showHighlight() && inBounds)
{
graphics.setColor(HIGHLIGHT);
graphics.fill(bounds);
}
else if (config.showGrid())
{
graphics.setColor(GRID);
graphics.fill(bounds);
}
}
return null;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek>
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 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 OWNER 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.runelite.client.plugins.inventorygrid;
import com.google.inject.Inject;
import com.google.inject.Provides;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
name = "Inventory Grid",
description = "Shows a grid over the inventory and a preview of where items will be dragged",
tags = {"items", "overlay"},
enabledByDefault = false
)
public class InventoryGridPlugin extends Plugin
{
@Inject
private InventoryGridOverlay overlay;
@Inject
private OverlayManager overlayManager;
@Override
public void startUp()
{
overlayManager.add(overlay);
}
@Override
public void shutDown()
{
overlayManager.remove(overlay);
}
@Provides
InventoryGridConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(InventoryGridConfig.class);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2017, Seth <Sethtroll3@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 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 OWNER 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.runelite.client.plugins.loginscreen;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("loginscreen")
public interface LoginScreenConfig extends Config
{
@ConfigItem(
keyName = "syncusername",
name = "Sync username",
description = "Syncs the username that is currently remembered between computers"
)
default boolean syncUsername()
{
return true;
}
@ConfigItem(
keyName = "pasteenabled",
name = "Ctrl-V paste",
description = "Enables Ctrl+V pasting on the login screen"
)
default boolean pasteEnabled()
{
return false;
}
@ConfigItem(
keyName = "username",
name = "",
description = "",
hidden = true
)
default String username()
{
return "";
}
@ConfigItem(
keyName = "username",
name = "",
description = ""
)
void username(String key);
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (c) 2017, Seth <Sethtroll3@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 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 OWNER 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.runelite.client.plugins.loginscreen;
import com.google.common.base.Strings;
import com.google.inject.Provides;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.KeyEvent;
import java.io.IOException;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.OSType;
@PluginDescriptor(
name = "Login Screen",
description = "Provides various enhancements for login screen"
)
@Slf4j
public class LoginScreenPlugin extends Plugin implements KeyListener
{
private static final int MAX_USERNAME_LENGTH = 254;
private static final int MAX_PASSWORD_LENGTH = 20;
private static final int MAX_PIN_LENGTH = 6;
@Inject
private Client client;
@Inject
private LoginScreenConfig config;
@Inject
private KeyManager keyManager;
private String usernameCache;
@Override
protected void startUp() throws Exception
{
applyUsername();
keyManager.registerKeyListener(this);
}
@Override
protected void shutDown() throws Exception
{
if (config.syncUsername())
{
client.getPreferences().setRememberedUsername(usernameCache);
}
keyManager.unregisterKeyListener(this);
}
@Provides
LoginScreenConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(LoginScreenConfig.class);
}
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
if (!config.syncUsername())
{
return;
}
if (event.getGameState() == GameState.LOGIN_SCREEN)
{
applyUsername();
}
else if (event.getGameState() == GameState.LOGGED_IN)
{
String username = "";
if (client.getPreferences().getRememberedUsername() != null)
{
username = client.getUsername();
}
if (config.username().equals(username))
{
return;
}
log.debug("Saving username: {}", username);
config.username(username);
}
}
@Subscribe
public void onSessionOpen(SessionOpen event)
{
// configuation for the account is available now, so update the username
applyUsername();
}
private void applyUsername()
{
if (!config.syncUsername())
{
return;
}
GameState gameState = client.getGameState();
if (gameState == GameState.LOGIN_SCREEN)
{
String username = config.username();
if (Strings.isNullOrEmpty(username))
{
return;
}
// Save it only once
if (usernameCache == null)
{
usernameCache = client.getPreferences().getRememberedUsername();
}
client.getPreferences().setRememberedUsername(username);
}
}
@Override
public void keyTyped(KeyEvent e)
{
}
@Override
public void keyPressed(KeyEvent e)
{
if (!config.pasteEnabled() || (
client.getGameState() != GameState.LOGIN_SCREEN &&
client.getGameState() != GameState.LOGIN_SCREEN_AUTHENTICATOR))
{
return;
}
// enable pasting on macOS with the Command (meta) key
boolean isModifierDown = OSType.getOSType() == OSType.MacOS ? e.isMetaDown() : e.isControlDown();
if (e.getKeyCode() == KeyEvent.VK_V && isModifierDown)
{
try
{
final String data = Toolkit
.getDefaultToolkit()
.getSystemClipboard()
.getData(DataFlavor.stringFlavor)
.toString()
.trim();
switch (client.getLoginIndex())
{
// Username/password form
case 2:
if (client.getCurrentLoginField() == 0)
{
// Truncate data to maximum username length if necessary
client.setUsername(data.substring(0, Math.min(data.length(), MAX_USERNAME_LENGTH)));
}
else
{
// Truncate data to maximum password length if necessary
client.setPassword(data.substring(0, Math.min(data.length(), MAX_PASSWORD_LENGTH)));
}
break;
// Authenticator form
case 4:
// Truncate data to maximum OTP code length if necessary
client.setOtp(data.substring(0, Math.min(data.length(), MAX_PIN_LENGTH)));
break;
}
}
catch (UnsupportedFlavorException | IOException ex)
{
log.warn("failed to fetch clipboard data", ex);
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
}
}

View File

@@ -152,34 +152,24 @@ public class RuneLitePlusPlugin extends Plugin
return configManager.getConfig(RuneLitePlusConfig.class);
}
private RuneLitePlusKeyListener keyListener;
private RuneLitePlusKeyListener keyListener = new RuneLitePlusKeyListener();
private int entered = -1;
private int enterIdx;
@Override
protected void startUp() throws Exception
{
entered = -1;
enterIdx = 0;
if (getConfig(configManager).customPresence())
if (config.customPresence())
{
ClientUI.currentPresenceName = ("RuneLitePlus");
ClientUI.frame.setTitle(ClientUI.currentPresenceName);
}
if (config.customPresence())
{
RuneLiteProperties.discordAppID = rlPlusDiscordApp;
discordService.close();
discordService.init();
}
else
{
RuneLiteProperties.discordAppID = rlDiscordApp;
discordService.close();
discordService.init();
}
entered = -1;
enterIdx = 0;
}
@Subscribe
@@ -196,26 +186,20 @@ public class RuneLitePlusPlugin extends Plugin
{
ClientUI.currentPresenceName = ("RuneLitePlus");
ClientUI.frame.setTitle(ClientUI.currentPresenceName);
}
else
{
ClientUI.currentPresenceName = ("RuneLite");
ClientUI.frame.setTitle(ClientUI.currentPresenceName);
}
if (config.customPresence())
{
RuneLiteProperties.discordAppID = rlPlusDiscordApp;
discordService.close();
discordService.init();
}
else
{
ClientUI.currentPresenceName = ("RuneLite");
ClientUI.frame.setTitle(ClientUI.currentPresenceName);
RuneLiteProperties.discordAppID = rlDiscordApp;
discordService.close();
discordService.init();
}
}
else if (!config.keyboardPin())
{
entered = -1;
@@ -253,7 +237,6 @@ public class RuneLitePlusPlugin extends Plugin
}
// log.debug("Registering key listener");
keyListener = new RuneLitePlusKeyListener();
keyManager.registerKeyListener(keyListener);
}
@@ -266,7 +249,6 @@ public class RuneLitePlusPlugin extends Plugin
entered = -1;
enterIdx = 0;
keyManager.unregisterKeyListener(keyListener);
keyListener = null;
return;
}

View File

@@ -27,12 +27,14 @@
package net.runelite.client.rs;
import com.google.common.io.ByteStreams;
import io.sigpipe.jbsdiff.Diff;
import io.sigpipe.jbsdiff.InvalidHeaderException;
import io.sigpipe.jbsdiff.Patch;
import java.applet.Applet;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -46,15 +48,16 @@ import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO;
import static net.runelite.client.rs.ClientUpdateCheckMode.CUSTOM;
import static net.runelite.client.rs.ClientUpdateCheckMode.NONE;
import static net.runelite.client.rs.ClientUpdateCheckMode.PATCH;
import net.runelite.http.api.RuneLiteAPI;
import okhttp3.Request;
import okhttp3.Response;
@@ -64,7 +67,9 @@ import org.apache.commons.compress.compressors.CompressorException;
@Singleton
public class ClientLoader
{
private static final File CUSTOMFILE = new File("replace me!");
private static final File CUSTOMFILE = new File("./injected-client/target/injected-client-1.5.27-SNAPSHOT.jar");
private static final File PATCHFILE = new File("replace me!");
private static final File OUTPUT = new File("replace me!");
private final ClientConfigLoader clientConfigLoader;
private ClientUpdateCheckMode updateCheckMode;
@@ -145,6 +150,44 @@ public class ClientLoader
}
}
if (updateCheckMode == PATCH)
{
log.debug("Creating patches");
int patchCount = 0;
Map<String, byte[]> injectedFile = new HashMap<>();
loadJar(injectedFile, CUSTOMFILE);
ByteArrayOutputStream patchOs = new ByteArrayOutputStream(756 * 1024);
Map<String, byte[]> patchJar = new HashMap<>();
for (Map.Entry<String, byte[]> file : zipFile.entrySet())
{
byte[] gamepackBytes = file.getValue();
byte[] injectedBytes = injectedFile.get(file.getKey());
byte[] patchBytes;
if (Arrays.equals(gamepackBytes, injectedBytes))
{
continue;
}
Diff.diff(gamepackBytes, injectedBytes, patchOs);
patchBytes = patchOs.toByteArray();
String patchName = file.getKey() + ".bs";
patchJar.put(patchName, patchBytes);
patchCount++;
patchOs.reset();
}
log.debug("Created patch files for {} files", patchCount);
saveJar(patchJar, PATCHFILE);
System.exit(0);
}
if (updateCheckMode == AUTO)
{
@@ -176,29 +219,7 @@ public class ClientLoader
if (updateCheckMode == CUSTOM)
{
JarInputStream fis = new JarInputStream(new FileInputStream(CUSTOMFILE));
byte[] tmp = new byte[4096];
ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024);
for (; ; )
{
JarEntry metadata = fis.getNextJarEntry();
if (metadata == null)
{
break;
}
buffer.reset();
for (; ; )
{
int n = fis.read(tmp);
if (n <= -1)
{
break;
}
buffer.write(tmp, 0, n);
}
zipFile.replace(metadata.getName(), buffer.toByteArray());
}
loadJar(zipFile, CUSTOMFILE);
}
String initialClass = config.getInitialClass();
@@ -246,4 +267,48 @@ public class ClientLoader
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(ClientLoader.class.getResourceAsStream("jagex.crt"));
return certificates.toArray(new Certificate[0]);
}
private static void saveJar(Map<String, byte[]> fileMap, File toFile) throws IOException
{
try (JarOutputStream jout = new JarOutputStream(new FileOutputStream(toFile), new Manifest()))
{
for (Map.Entry<String, byte[]> entry : fileMap.entrySet())
{
JarEntry e = new JarEntry(entry.getKey());
jout.putNextEntry(e);
byte[] data = entry.getValue();
jout.write(data);
jout.closeEntry();
}
}
}
private static void loadJar(Map<String, byte[]> toMap, File fromFile) throws IOException
{
JarInputStream fis = new JarInputStream(new FileInputStream(fromFile));
byte[] tmp = new byte[4096];
ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024);
for (; ; )
{
JarEntry metadata = fis.getNextJarEntry();
if (metadata == null)
{
break;
}
buffer.reset();
for (; ; )
{
int n = fis.read(tmp);
if (n <= -1)
{
break;
}
buffer.write(tmp, 0, n);
}
toMap.put(metadata.getName(), buffer.toByteArray());
}
}
}

View File

@@ -29,5 +29,6 @@ public enum ClientUpdateCheckMode
AUTO,
NONE,
VANILLA,
CUSTOM
CUSTOM,
PATCH
}