Skip to content

Commit

Permalink
Add kephri swarmer feature (#106)
Browse files Browse the repository at this point in the history
* add swarmer feature

* clean up swarmer feature

* clean up curlies

* fix indentation issues

* fix curlies again

* more code formatting

* disable when outside toa areas

* track spawn wave by tick

* use animation change events

* remove unused injected fields

* un-static state fields

* remove unused cardinality after tick-based tracking

* un-star import

* constant room end message

* use groupingBy and jawt outline in overlay

* panel changes

* only rebuild panel models

* load recent raids on startup

* separate panel from overlay, merge

* reset on room wipe

* split out data class from writer

* use injected gson

* construct leak data in-run

* remove unused swarmnpc fields

* build panel on edt

* simplify some data manager stuff

* move io to its own thread

* load raid list after save

* prevent early wave number increment

* sort leaks table

---------

Co-authored-by: Rhea <[email protected]>
  • Loading branch information
FiveNine and LlemonDuck authored Oct 20, 2024
1 parent 092ad26 commit be0f17f
Show file tree
Hide file tree
Showing 11 changed files with 832 additions and 9 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ Font style and size can be controlled by the matching options.

</details>

<details>
<summary>Kephri</summary>

### 🚀 Swarmer

Displays wave numbers on scarab swarms in the kephri room as they spawn.
The side panel will show logs of previous raid's leaked swarms.
Font color, style and size can be controlled by the matching options.
![Swarmer Example](https://imgur.com/msneEOQ.png "Swarmer Example")

</details>

<details>
<summary>Path of Apmeken</summary>

Expand Down
105 changes: 96 additions & 9 deletions src/main/java/com/duckblade/osrs/toa/TombsOfAmascutConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.duckblade.osrs.toa;

import com.duckblade.osrs.toa.features.QuickProceedSwaps.QuickProceedEnableMode;
import com.duckblade.osrs.toa.features.boss.kephri.swarmer.SwarmerFonts;
import com.duckblade.osrs.toa.features.boss.kephri.swarmer.SwarmerPanelManager;
import com.duckblade.osrs.toa.features.hporbs.HpOrbMode;
import com.duckblade.osrs.toa.features.scabaras.ScabarasHelperMode;
import com.duckblade.osrs.toa.features.scabaras.SkipObeliskOverlay;
Expand All @@ -9,7 +11,9 @@
import com.duckblade.osrs.toa.features.updatenotifier.UpdateNotifier;
import com.duckblade.osrs.toa.util.FontStyle;
import com.duckblade.osrs.toa.util.HighlightMode;
import java.awt.Color;

import java.awt.*;

import net.runelite.client.config.Alpha;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
Expand Down Expand Up @@ -42,34 +46,42 @@ public interface TombsOfAmascutConfig extends Config
)
String SECTION_AKKHA = "sectionAkkha";

@ConfigSection(
name = "Kephri",
description = "Configuration for the Kephri room.",
position = 2,
closedByDefault = true
)
String SECTION_KEPHRI = "sectionKephri";

@ConfigSection(
name = "Path of Apmeken",
description = "Options for the Path of Apmeken.",
position = 2,
position = 3,
closedByDefault = true
)
String SECTION_APMEKEN = "sectionApmeken";

@ConfigSection(
name = "Path of Het",
description = "Helpers for the Path of Het.",
position = 3,
position = 4,
closedByDefault = true
)
String SECTION_HET = "sectionHet";

@ConfigSection(
name = "Path of Scabaras",
description = "Options for the puzzles in the Path of Scabaras.",
position = 4,
position = 5,
closedByDefault = true
)
String SECTION_SCABARAS = "sectionScabaras";

@ConfigSection(
name = "Burial Tomb",
description = "Configuration for the burial tomb.",
position = 5,
position = 6,
closedByDefault = true
)
String SECTION_BURIAL_TOMB = "sectionBurialTomb";
Expand All @@ -78,31 +90,31 @@ public interface TombsOfAmascutConfig extends Config
name = "Points Tracker",
description = "<html>Tracks points for the raid, used in calculating drop chance." +
"<br/>NOTE: For teams, you MUST use the RuneLite Party plugin to receive team drop chance.</html>",
position = 6,
position = 7,
closedByDefault = true
)
String SECTION_POINTS_TRACKER = "sectionPointsTracker";

@ConfigSection(
name = "Invocation Presets",
description = "Save presets of invocations to quickly restore your invocations between runs of different types.",
position = 7,
position = 8,
closedByDefault = true
)
String SECTION_INVOCATION_PRESETS = "invocationPresetsSection";

@ConfigSection(
name = "Invocation Screenshot",
description = "All config options related to the Invocation Screenshot functionality",
position = 8,
position = 9,
closedByDefault = true
)
String SECTION_INVOCATION_SCREENSHOT = "invocationScreenshotSection";

@ConfigSection(
name = "Time Tracking",
description = "Time tracking and splits.",
position = 9,
position = 10,
closedByDefault = true
)
String SECTION_TIME_TRACKING = "sectionTimeTracking";
Expand Down Expand Up @@ -147,6 +159,81 @@ default int akkhaFontSize()
return 12;
}

// Kephri
@ConfigItem(
keyName = "swarmerOverlay",
name = "Swarmer Overlay",
description = "Overlay swarm wave number.",
position = 0,
section = SECTION_KEPHRI
)
default boolean swarmerOverlay()
{
return false;
}

@ConfigItem(
name = "Font Type",
description = "Type of font",
position = 1,
keyName = "fontType",
section = SECTION_KEPHRI
)
default SwarmerFonts swarmerFontType()
{
return SwarmerFonts.ARIAL;
}

@ConfigItem(
name = "Use Bold Font",
description = "Font style of swarm overlay.",
position = 2,
keyName = "useBoldFont",
section = SECTION_KEPHRI
)
default boolean useBoldFont()
{
return true;
}

@ConfigItem(
name = "Font Size",
description = "Font size of swarm overlay.",
position = 3,
keyName = "swarmerFontSize",
section = SECTION_KEPHRI
)
@Units(Units.PIXELS)
@Range(min = 12)
default int swarmerFontSize()
{
return 12;
}

@ConfigItem(
name = "Side Panel",
description = "Show a side panel with summary data for previous raids.",
position = 4,
keyName = "swarmerSidePanel",
section = SECTION_KEPHRI
)
default SwarmerPanelManager.PanelMode swarmerSidePanel()
{
return SwarmerPanelManager.PanelMode.NEVER;
}

@ConfigItem(
name = "Font Color",
description = "Font color of swarm overlay.",
position = 4,
keyName = "swarmerFontColor",
section = SECTION_KEPHRI
)
default Color swarmerFontColor()
{
return Color.WHITE;
}

// Apmeken

@ConfigItem(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.duckblade.osrs.toa.features.boss.kephri.swarmer;

import lombok.Data;
import net.runelite.api.NPC;

@Data
public class SwarmNpc
{
private final NPC npc;
private final int waveSpawned;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.duckblade.osrs.toa.features.boss.kephri.swarmer;

import com.duckblade.osrs.toa.TombsOfAmascutPlugin;
import com.duckblade.osrs.toa.module.PluginLifecycleComponent;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.RequiredArgsConstructor;

@Singleton
@RequiredArgsConstructor(onConstructor_ = @Inject)
public class SwarmerDataManager implements PluginLifecycleComponent
{

private static final int MAX_RECENT_RAIDS = 10;
public static final Path SWARMS_DIRECTORY = new File(TombsOfAmascutPlugin.TOA_FOLDER, "kephri-swarms").toPath();

private final Gson gson;

private ExecutorService executor;

@Override
public void startUp()
{
executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("ToA-SwarmerDataManager-%d").build());
}

@Override
public void shutDown()
{
executor.shutdown();
}

public CompletableFuture<List<String>> getRaidList()
{
return CompletableFuture.supplyAsync(() ->
{
try
{
if (!Files.exists(SWARMS_DIRECTORY))
{
return Collections.emptyList();
}

try (Stream<Path> files = Files.list(SWARMS_DIRECTORY))
{
return files.filter(f -> f.getFileName().toString().endsWith(".json"))
.sorted(Comparator.reverseOrder())
.limit(MAX_RECENT_RAIDS)
.map(f -> f.getFileName().toString().replace(".json", ""))
.map(s -> s.replace('_', ':'))
.collect(Collectors.toList());
}
}
catch (Exception ignored)
{
}

return Collections.emptyList();
}, executor);
}

public CompletableFuture<List<SwarmerRoomData>> getRaidData(String raidUnsafe)
{
return CompletableFuture.supplyAsync(() ->
{
String raid = raidUnsafe.replace(':', '_');

if (!Files.exists(SWARMS_DIRECTORY))
{
return Collections.emptyList();
}
if (!Files.exists(SWARMS_DIRECTORY.resolve(raid + ".json")))
{
return Collections.emptyList();
}

try (FileReader reader = new FileReader(SWARMS_DIRECTORY.resolve(raid + ".json").toFile()))
{
Type listType = new TypeToken<List<SwarmerRoomData>>()
{
}.getType();
return gson.fromJson(reader, listType);
}
catch (Exception ignored)
{
return Collections.emptyList();
}
}, executor);
}

public CompletableFuture<Void> saveRaidData(List<SwarmerRoomData> raidDataList)
{
return CompletableFuture.runAsync(() ->
{
String raidName = new SimpleDateFormat("yyyy-MM-dd HH_mm_ss").format(new Date());
try
{
if (!Files.exists(SWARMS_DIRECTORY))
{
Files.createDirectories(SWARMS_DIRECTORY);
}
Files.writeString(
SWARMS_DIRECTORY.resolve(raidName + ".json"),
gson.toJson(raidDataList),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
);
}
catch (Exception ignored)
{
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.duckblade.osrs.toa.features.boss.kephri.swarmer;

import lombok.Getter;

@Getter
public enum SwarmerFonts
{
REGULAR("RS Regular"),
ARIAL("Arial"),
CAMBRIA("Cambria"),
ROCKWELL("Rockwell"),
SEGOE_UI("Segoe Ui"),
TIMES_NEW_ROMAN("Times New Roman"),
VERDANA("Verdana"),
DIALOG("DIALOG"),
RUNESCAPE("RuneScape");

private final String name;

public String toString()
{
return this.name;
}

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

}
Loading

0 comments on commit be0f17f

Please sign in to comment.