Skip to content

Commit

Permalink
Merge branch '221-1.10.27'
Browse files Browse the repository at this point in the history
  • Loading branch information
zeruth committed Apr 17, 2024
2 parents 96f435b + 8ca32fe commit 123c024
Show file tree
Hide file tree
Showing 162 changed files with 5,021 additions and 1,097 deletions.
2 changes: 1 addition & 1 deletion cache/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<parent>
<groupId>net.runelite</groupId>
<artifactId>runelite-parent</artifactId>
<version>1.10.26.4</version>
<version>1.10.27</version>
</parent>

<artifactId>cache</artifactId>
Expand Down
75 changes: 75 additions & 0 deletions cache/src/main/java/net/runelite/cache/FontManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2024, Christopher Brown <[email protected]>
* 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.cache;

import net.runelite.cache.definitions.FontDefinition;
import net.runelite.cache.definitions.loaders.FontLoader;
import net.runelite.cache.fs.Archive;
import net.runelite.cache.fs.FSFile;
import net.runelite.cache.fs.Index;
import net.runelite.cache.fs.Storage;
import net.runelite.cache.fs.Store;
import net.runelite.cache.util.Djb2;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class FontManager
{
private final Store store;
private final Map<Integer, FontDefinition> fonts = new HashMap<>();

public FontManager(Store store)
{
this.store = store;
}

public void load() throws IOException
{
Storage storage = store.getStorage();
Index index = store.getIndex(IndexType.FONTS);
FontLoader fontLoader = new FontLoader();

for (Archive archive : index.getArchives())
{
byte[] data = storage.loadArchive(archive);
FSFile file = archive.getFiles(data).getFiles().get(0);
FontDefinition fontDefinition = fontLoader.load(file.getContents());

fonts.put(archive.getNameHash(), fontDefinition);
}
}

public FontDefinition getFont(int nameHash)
{
return fonts.get(nameHash);
}

public FontDefinition findFontByName(String name)
{
int nameHash = Djb2.hash(name);
return this.getFont(nameHash);
}
}
47 changes: 47 additions & 0 deletions cache/src/main/java/net/runelite/cache/FontName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024, Christopher Brown <[email protected]>
* 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.cache;

public enum FontName
{
PLAIN_11("p11_full"),
PLAIN_12("p12_full"),
BOLD_12("b12_full"),
VERDANA_11("verdana_11pt_regular"),
VERDANA_13("verdana_13pt_regular"),
VERDANA_15("verdana_15pt_regular");

private String name;

FontName(String name)
{
this.name = name;
}

public String getName()
{
return this.name;
}
}
122 changes: 115 additions & 7 deletions cache/src/main/java/net/runelite/cache/MapImageDumper.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import net.runelite.cache.definitions.AreaDefinition;
import net.runelite.cache.definitions.FontDefinition;
import net.runelite.cache.definitions.ObjectDefinition;
import net.runelite.cache.definitions.OverlayDefinition;
import net.runelite.cache.definitions.SpriteDefinition;
import net.runelite.cache.definitions.UnderlayDefinition;
import net.runelite.cache.definitions.WorldMapElementDefinition;
import net.runelite.cache.definitions.loaders.OverlayLoader;
import net.runelite.cache.definitions.loaders.SpriteLoader;
import net.runelite.cache.definitions.loaders.UnderlayLoader;
Expand Down Expand Up @@ -94,6 +96,8 @@ public class MapImageDumper
private final RegionLoader regionLoader;
private final AreaManager areas;
private final SpriteManager sprites;
private final FontManager fonts;
private final WorldMapManager worldMapManager;
private RSTextureProvider rsTextureProvider;
private final ObjectManager objectManager;

Expand All @@ -117,6 +121,10 @@ public class MapImageDumper
@Setter
private boolean renderIcons = true;

@Getter
@Setter
private boolean renderLabels = true;

@Getter
@Setter
private boolean transparency = false;
Expand All @@ -136,6 +144,8 @@ public MapImageDumper(Store store, RegionLoader regionLoader)
this.regionLoader = regionLoader;
this.areas = new AreaManager(store);
this.sprites = new SpriteManager(store);
this.fonts = new FontManager(store);
this.worldMapManager = new WorldMapManager(store);
this.objectManager = new ObjectManager(store);
}

Expand Down Expand Up @@ -218,6 +228,8 @@ public MapImageDumper load() throws IOException
areas.load();
sprites.load();
loadSprites();
fonts.load();
worldMapManager.load();

return this;
}
Expand Down Expand Up @@ -253,6 +265,7 @@ public BufferedImage drawMap(int z)
drawMap(image, z);
drawObjects(image, z);
drawMapIcons(image, z);
drawMapLabels(image, z);

return image;
}
Expand Down Expand Up @@ -919,6 +932,57 @@ private void drawMapIcons(BufferedImage image, int z)
}
}

private void drawMapLabels(BufferedImage image, int z)
{
if (!renderLabels)
{
return;
}

FontName[] fontSizes = new FontName[] { FontName.VERDANA_11, FontName.VERDANA_13, FontName.VERDANA_15 };
List<WorldMapElementDefinition> elements = worldMapManager.getElements();
for (WorldMapElementDefinition element : elements)
{
AreaDefinition area = areas.getArea(element.getAreaDefinitionId());
Position worldPosition = element.getWorldPosition();
if (area == null || area.getName() == null || worldPosition.getZ() != z)
{
continue;
}

FontName fontSize = fontSizes[area.getTextScale()];
FontDefinition font = fonts.findFontByName(fontSize.getName());
String areaLabel = area.getName();
String[] lines = areaLabel.split("<br>");
int ascent = 0;

for (String line : lines)
{
int advance = 0;
int stringWidth = font.stringWidth(line);
for (int i = 0; i < line.length(); ++i)
{
char c = line.charAt(i);
SpriteDefinition sprite = sprites.findSpriteByArchiveName(fontSize.getName(), c);
if (sprite.getWidth() != 0 && sprite.getHeight() != 0)
{
int drawX = worldPosition.getX() - regionLoader.getLowestX().getBaseX();
int drawY = regionLoader.getHighestY().getBaseY() - worldPosition.getY() + Region.Y - 2;
blitGlyph(image,
(drawX * MAP_SCALE) + advance - (stringWidth / 2),
(drawY * MAP_SCALE) + ascent - (font.getAscent() / 2),
area.getTextColor(),
sprite
);
}

advance += font.getAdvances()[c];
}
ascent += font.getAscent() / 2;
}
}
}

private ObjectDefinition findObject(int id)
{
return objectManager.getObject(id);
Expand Down Expand Up @@ -1032,13 +1096,9 @@ private void drawMapIcons(BufferedImage img, Region region, int z, int drawBaseX
{
int localX = location.getPosition().getX() - region.getBaseX();
int localY = location.getPosition().getY() - region.getBaseY();
boolean isBridge = (region.getTileSetting(1, localX, localY) & 2) != 0;

int tileZ = z + (isBridge ? 1 : 0);
int localZ = location.getPosition().getZ();
if (z != 0 && localZ != tileZ)
if (z != location.getPosition().getZ())
{
// draw all icons on z=0
continue;
}

Expand All @@ -1058,11 +1118,36 @@ private void drawMapIcons(BufferedImage img, Region region, int z, int drawBaseX
assert sprite != null;

blitIcon(img,
2 + (drawX * MAP_SCALE) - (sprite.getMaxWidth() / 2),
2 + (drawY * MAP_SCALE) - (sprite.getMaxHeight() / 2),
(drawX * MAP_SCALE) - (sprite.getMaxWidth() / 2),
(drawY * MAP_SCALE) - (sprite.getMaxHeight() / 2),
sprite);
}
}

// Draw the intermap link icons which are not stored with the map locations
List<WorldMapElementDefinition> elements = worldMapManager.getElements();
for (WorldMapElementDefinition element : elements)
{
AreaDefinition area = areas.getArea(element.getAreaDefinitionId());
Position worldPosition = element.getWorldPosition();
int regionX = worldPosition.getX() / Region.X;
int regionY = worldPosition.getY() / Region.Y;

if (area == null || area.getName() != null || worldPosition.getZ() != z || regionX != region.getRegionX() || regionY != region.getRegionY())
{
continue;
}

int localX = worldPosition.getX() - region.getBaseX();
int localY = worldPosition.getY() - region.getBaseY();
int drawX = drawBaseX + localX;
int drawY = drawBaseY + (Region.Y - 1 - localY);
SpriteDefinition sprite = sprites.findSprite(area.spriteId, 0);
blitIcon(img,
(drawX * MAP_SCALE) - (sprite.getMaxWidth() / 2),
(drawY * MAP_SCALE) - (sprite.getMaxHeight() / 2),
sprite);
}
}

private void loadRegions() throws IOException
Expand Down Expand Up @@ -1164,4 +1249,27 @@ private void blitIcon(BufferedImage dst, int x, int y, SpriteDefinition sprite)
}
}
}

private void blitGlyph(BufferedImage dst, int x, int y, int color, SpriteDefinition glyph)
{
int[] pixels = glyph.getPixels();
int[] shadowPixels = new int[pixels.length];
for (int i = 0; i < pixels.length; ++i)
{
if (pixels[i] != 0)
{
pixels[i] = color;
shadowPixels[i] = 0xFF000000;
}
}
SpriteDefinition shadow = new SpriteDefinition();
shadow.setPixels(shadowPixels);
shadow.setOffsetX(glyph.getOffsetX());
shadow.setOffsetY(glyph.getOffsetY());
shadow.setWidth(glyph.getWidth());
shadow.setHeight(glyph.getHeight());

blitIcon(dst, x + 1, y + 1, shadow);
blitIcon(dst, x, y, glyph);
}
}
19 changes: 18 additions & 1 deletion cache/src/main/java/net/runelite/cache/SpriteManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import net.runelite.cache.definitions.SpriteDefinition;
import net.runelite.cache.definitions.exporters.SpriteExporter;
import net.runelite.cache.definitions.loaders.SpriteLoader;
Expand All @@ -39,11 +41,13 @@
import net.runelite.cache.fs.Index;
import net.runelite.cache.fs.Storage;
import net.runelite.cache.fs.Store;
import net.runelite.cache.util.Djb2;

public class SpriteManager implements SpriteProvider
{
private final Store store;
private final Multimap<Integer, SpriteDefinition> sprites = LinkedListMultimap.create();
private final Map<Integer, Integer> spriteIdsByArchiveNameHash = new HashMap<>();

public SpriteManager(Store store)
{
Expand All @@ -65,6 +69,7 @@ public void load() throws IOException
for (SpriteDefinition sprite : defs)
{
sprites.put(sprite.getId(), sprite);
spriteIdsByArchiveNameHash.put(a.getNameHash(), sprite.getId());
}
}
}
Expand Down Expand Up @@ -93,11 +98,23 @@ public BufferedImage getSpriteImage(SpriteDefinition sprite)
return image;
}

public SpriteDefinition findSpriteByArchiveName(String name, int frameId)
{
int nameHash = Djb2.hash(name);
Integer spriteId = spriteIdsByArchiveNameHash.get(nameHash);
if (spriteId != null)
{
return this.findSprite(spriteId, frameId);
}

return null;
}

public void export(File outDir) throws IOException
{
for (SpriteDefinition sprite : sprites.values())
{
// I don't know why this happens
// Some sprites like ones for non-printable font characters do not have sizes
if (sprite.getHeight() <= 0 || sprite.getWidth() <= 0)
{
continue;
Expand Down
Loading

0 comments on commit 123c024

Please sign in to comment.