Skip to content

Commit 2049faf

Browse files
committed
Initial release: Faction Relationships mod
1 parent 1d5871e commit 2049faf

13 files changed

Lines changed: 434 additions & 1 deletion

File tree

.gitignore

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Cursor IDE
2+
.cursor/
3+
4+
# Developer config (copy compile.local.example.bat to compile.local.bat and set your paths)
5+
FactionRelationships/compile.local.bat
6+
7+
# Build output (from compile.bat; folder and zip include version from mod_info.json)
8+
FactionRelationships-*/
9+
FactionRelationships-*.zip
10+
11+
# Java
12+
*.class
13+
*.jar
14+
target/
15+
build/
16+
out/
17+
.gradle/
18+
19+
# IDE
20+
.idea/
21+
*.iml
22+
.vscode/
23+
*.swp
24+
*.swo
25+
*~
26+
27+
# OS
28+
Thumbs.db
29+
.DS_Store
30+
desktop.ini
31+
32+
# Logs and temp
33+
*.log
34+
*.bak
35+
*.tmp
36+
*.temp
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Compilation Reference Guide
2+
3+
## Project Overview
4+
5+
**Faction Relationships** – A Starsector mod that shows a list of factions and their relationship with the player on the main navigation screen.
6+
7+
- **Mod ID**: `factionrelationships`
8+
- **Game Version**: `0.98a-RC8`
9+
- **Mod Plugin**: `com.factionrelationships.FactionRelationshipsPlugin`
10+
11+
## Prerequisites
12+
13+
1. **JDK 17** – Starsector 0.98a uses Java 17. Install JDK 17 and run `javac -version`.
14+
2. **Starsector** – JARs are taken from your game install (the folder that contains `starsector-core`).
15+
16+
## Developer config (optional)
17+
18+
To avoid editing `compile.bat` and to keep your local paths out of the repo:
19+
20+
1. Copy `FactionRelationships/compile.local.example.bat` to `FactionRelationships/compile.local.bat`.
21+
2. Edit `compile.local.bat` and set `GAME_DIR` to your Starsector install directory.
22+
23+
`compile.local.bat` is gitignored; only the example file is committed. The main `compile.bat` loads it automatically when present.
24+
25+
## Project Structure
26+
27+
```
28+
FactionRelationships/
29+
├── mod_info.json
30+
├── config/
31+
│ └── faction_relationships_config.json # optional: maxFactions (default 15, clamped 1–50)
32+
├── src/
33+
│ └── com/factionrelationships/
34+
│ ├── FactionRelationshipsPlugin.java
35+
│ └── FactionRelationshipsUIRenderer.java
36+
├── compile.local.example.bat # copy to compile.local.bat (gitignored) to set GAME_DIR
37+
└── COMPILATION.md
38+
```
39+
40+
Output: `FactionRelationships-<version>/` (folder and zip), where `<version>` comes from `mod_info.json` (e.g. `FactionRelationships-1.0.0/`, `FactionRelationships-1.0.0.zip`). Contains `classes/`, `jars/FactionRelationships.jar`, and `config/`.
41+
42+
## Compile
43+
44+
From the repo root, run the build script:
45+
46+
```batch
47+
FactionRelationships\compile.bat
48+
```
49+
50+
Or manually:
51+
52+
```batch
53+
set GAME_DIR=YOUR_STARSECTOR_PATH
54+
set CORE=%GAME_DIR%\starsector-core
55+
set VERSION=1.0.0
56+
javac -encoding UTF-8 -cp "%CORE%\starfarer.api.jar;%CORE%\starfarer_obf.jar;%CORE%\log4j-1.2.9.jar;%CORE%\lwjgl.jar;%CORE%\lwjgl_util.jar" -d FactionRelationships-%VERSION%\classes FactionRelationships\src\com\factionrelationships\*.java
57+
jar cvf FactionRelationships-%VERSION%\jars\FactionRelationships.jar -C FactionRelationships-%VERSION%\classes .
58+
```
59+
60+
Set `GAME_DIR` before running (e.g. via `compile.local.bat` as above, or in the batch session).
61+
62+
## Package and Install
63+
64+
1. The build script copies `mod_info.json` and config into the versioned package folder (e.g. `FactionRelationships-1.0.0/`).
65+
2. Copy that folder into your game `mods` folder, then rename to `FactionRelationships` for the game to load it, or use the zip:
66+
67+
```
68+
xcopy /E /I FactionRelationships-1.0.0 "YOUR_STARSECTOR_PATH\mods\FactionRelationships\"
69+
```
70+
Or extract `FactionRelationships-1.0.0.zip` into `mods` and rename the extracted folder to `FactionRelationships`.
71+
72+
3. Final layout in your game `mods` folder:
73+
74+
```
75+
mods\FactionRelationships\
76+
├── mod_info.json
77+
├── config\
78+
│ └── faction_relationships_config.json
79+
└── jars\
80+
└── FactionRelationships.jar
81+
```
82+
83+
To change how many factions are shown, edit `config/faction_relationships_config.json` and set `maxFactions` (1–50). Default is 15.
84+
85+
## Quick Reference
86+
87+
- **Game directory**: Set `GAME_DIR` in `compile.local.bat` (recommended) or in `compile.bat` / manual commands.
88+
- **Source**: `FactionRelationships/src/com/factionrelationships/`
89+
- **Output**: `FactionRelationships-<version>/` and `FactionRelationships-<version>.zip` (version from `mod_info.json`); JAR at `jars/FactionRelationships.jar` inside the package.

FactionRelationships/compile.bat

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@echo off
2+
REM Load developer config if present (copy compile.local.example.bat to compile.local.bat and set GAME_DIR)
3+
if exist "%~dp0compile.local.bat" call "%~dp0compile.local.bat"
4+
if not defined GAME_DIR set GAME_DIR=YOUR_STARSECTOR_PATH
5+
6+
set CORE=%GAME_DIR%\starsector-core
7+
if not exist "%CORE%\starfarer.api.jar" (
8+
echo Error: Starsector path not found.
9+
echo Copy FactionRelationships\compile.local.example.bat to compile.local.bat and set GAME_DIR to your Starsector install directory.
10+
exit /b 1
11+
)
12+
13+
REM Read version from mod_info.json for package and zip names
14+
for /f "delims=" %%v in ('powershell -NoProfile -Command "(Get-Content '%~dp0mod_info.json' -Raw | ConvertFrom-Json).version"') do set VERSION=%%v
15+
set PKG=FactionRelationships-%VERSION%
16+
17+
set SRC=src\com\factionrelationships
18+
set OUT=..\%PKG%\classes
19+
set JAR=..\%PKG%\jars\FactionRelationships.jar
20+
21+
if not exist "%OUT%" mkdir "%OUT%"
22+
if not exist "..\%PKG%\jars" mkdir "..\%PKG%\jars"
23+
24+
echo Compiling...
25+
javac -encoding UTF-8 -cp "%CORE%\starfarer.api.jar;%CORE%\starfarer_obf.jar;%CORE%\json.jar;%CORE%\log4j-1.2.9.jar;%CORE%\lwjgl.jar;%CORE%\lwjgl_util.jar" -d "%OUT%" "%SRC%\FactionRelationshipsPlugin.java" "%SRC%\FactionRelationshipsUIRenderer.java"
26+
if errorlevel 1 (
27+
echo Compilation failed.
28+
exit /b 1
29+
)
30+
31+
echo Creating JAR...
32+
jar cvf "%JAR%" -C "%OUT%" .
33+
if errorlevel 1 (
34+
echo JAR creation failed.
35+
exit /b 1
36+
)
37+
38+
echo Copying mod_info.json and config to package...
39+
copy /Y "mod_info.json" "..\%PKG%\mod_info.json" >nul
40+
if exist "config" xcopy /E /I /Y "config" "..\%PKG%\config" >nul
41+
42+
echo Creating %PKG%.zip...
43+
powershell -NoProfile -Command "Compress-Archive -Path '..\%PKG%' -DestinationPath '..\%PKG%.zip' -Force"
44+
45+
echo Done. Install by copying %PKG% to Starsector\mods\FactionRelationships\ (or extract %PKG%.zip into mods)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@echo off
2+
REM Copy this file to compile.local.bat and set your paths.
3+
REM compile.local.bat is gitignored and will be used by compile.bat when present.
4+
5+
set GAME_DIR=YOUR_STARSECTOR_PATH
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"maxFactions": 15
3+
}

FactionRelationships/mod_info.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"id": "factionrelationships",
3+
"name": "Faction Relationships",
4+
"author": "boop",
5+
"version": "1.0.0",
6+
"description": "Shows a list of factions and their relationship with the player on the main navigation screen.",
7+
"gameVersion": "0.98a-RC8",
8+
"jars": ["jars/FactionRelationships.jar"],
9+
"modPlugin": "com.factionrelationships.FactionRelationshipsPlugin"
10+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.factionrelationships;
2+
3+
import com.fs.starfarer.api.BaseModPlugin;
4+
import com.fs.starfarer.api.Global;
5+
import org.apache.log4j.Logger;
6+
7+
public class FactionRelationshipsPlugin extends BaseModPlugin {
8+
9+
private static Logger log;
10+
11+
@Override
12+
public void onApplicationLoad() throws Exception {
13+
log = Global.getLogger(FactionRelationshipsPlugin.class);
14+
log.info("Faction Relationships mod loaded.");
15+
}
16+
17+
@Override
18+
public void onGameLoad(boolean newGame) {
19+
Global.getSector().getListenerManager().addListener(new FactionRelationshipsUIRenderer(), true);
20+
if (log != null) {
21+
log.info("Faction Relationships UI renderer registered.");
22+
}
23+
}
24+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package com.factionrelationships;
2+
3+
import com.fs.starfarer.api.Global;
4+
import com.fs.starfarer.api.campaign.FactionAPI;
5+
import com.fs.starfarer.api.campaign.econ.EconomyAPI;
6+
import com.fs.starfarer.api.campaign.econ.MarketAPI;
7+
import com.fs.starfarer.api.campaign.listeners.CampaignUIRenderingListener;
8+
import com.fs.starfarer.api.characters.RelationshipAPI;
9+
import com.fs.starfarer.api.combat.ViewportAPI;
10+
import com.fs.starfarer.api.ui.Fonts;
11+
import com.fs.starfarer.api.ui.LabelAPI;
12+
import com.fs.starfarer.api.ui.PositionAPI;
13+
14+
import org.json.JSONException;
15+
import org.json.JSONObject;
16+
17+
import java.awt.Color;
18+
import java.io.IOException;
19+
import java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.Comparator;
22+
import java.util.HashSet;
23+
import java.util.List;
24+
import java.util.Set;
25+
26+
public class FactionRelationshipsUIRenderer implements CampaignUIRenderingListener {
27+
28+
private static final float X_PAD = 20f;
29+
private static final float Y_PAD = 80f;
30+
private static final float LINE_HEIGHT = 14f;
31+
private static final int DEFAULT_MAX_FACTIONS = 15;
32+
private static final int MIN_MAX_FACTIONS = 1;
33+
private static final int MAX_MAX_FACTIONS = 50;
34+
private static final String CONFIG_PATH = "config/faction_relationships_config.json";
35+
private static final String MOD_ID = "factionrelationships";
36+
37+
private static Integer cachedMaxFactions = null;
38+
39+
private static int getMaxFactions() {
40+
if (cachedMaxFactions != null) {
41+
return cachedMaxFactions.intValue();
42+
}
43+
try {
44+
JSONObject config = Global.getSettings().loadJSON(CONFIG_PATH, MOD_ID);
45+
int value = config.optInt("maxFactions", DEFAULT_MAX_FACTIONS);
46+
cachedMaxFactions = Integer.valueOf(Math.max(MIN_MAX_FACTIONS, Math.min(MAX_MAX_FACTIONS, value)));
47+
} catch (IOException e) {
48+
cachedMaxFactions = Integer.valueOf(DEFAULT_MAX_FACTIONS);
49+
} catch (JSONException e) {
50+
cachedMaxFactions = Integer.valueOf(DEFAULT_MAX_FACTIONS);
51+
}
52+
return cachedMaxFactions.intValue();
53+
}
54+
55+
@Override
56+
public void renderInUICoordsBelowUI(ViewportAPI viewport) {
57+
// no-op; draw above UI
58+
}
59+
60+
@Override
61+
public void renderInUICoordsAboveUIBelowTooltips(ViewportAPI viewport) {
62+
renderPanel(viewport);
63+
}
64+
65+
@Override
66+
public void renderInUICoordsAboveUIAndTooltips(ViewportAPI viewport) {
67+
// no-op; we use AboveUIBelowTooltips so tooltips can show on top
68+
}
69+
70+
private void renderPanel(ViewportAPI viewport) {
71+
if (Global.getSector() == null || Global.getSector().getPlayerFleet() == null) {
72+
return;
73+
}
74+
75+
Set<String> factionIdsWithMarkets = new HashSet<String>();
76+
EconomyAPI economy = Global.getSector().getEconomy();
77+
if (economy != null) {
78+
for (MarketAPI market : economy.getMarketsCopy()) {
79+
if (market.getFaction() != null) {
80+
factionIdsWithMarkets.add(market.getFactionId());
81+
}
82+
}
83+
}
84+
85+
List<FactionAPI> factions = new ArrayList<FactionAPI>();
86+
for (FactionAPI faction : Global.getSector().getAllFactions()) {
87+
if (faction.isPlayerFaction()) {
88+
continue;
89+
}
90+
if (!factionIdsWithMarkets.contains(faction.getId())) {
91+
continue;
92+
}
93+
factions.add(faction);
94+
}
95+
96+
Collections.sort(factions, new Comparator<FactionAPI>() {
97+
@Override
98+
public int compare(FactionAPI a, FactionAPI b) {
99+
float relA = a.getRelToPlayer().getRel();
100+
float relB = b.getRelToPlayer().getRel();
101+
return Float.compare(relA, relB);
102+
}
103+
});
104+
105+
int maxFactions = getMaxFactions();
106+
int count = Math.min(factions.size(), maxFactions);
107+
if (count == 0) {
108+
return;
109+
}
110+
111+
float screenW = Global.getSettings().getScreenWidth();
112+
float screenH = Global.getSettings().getScreenHeight();
113+
114+
List<LabelAPI> labels = new ArrayList<LabelAPI>();
115+
for (int i = 0; i < count; i++) {
116+
FactionAPI faction = factions.get(i);
117+
RelationshipAPI rel = faction.getRelToPlayer();
118+
float repValue = rel.getRel();
119+
String levelName = rel.getLevel().getDisplayName();
120+
String line = faction.getDisplayName() + " " + formatRepValue(repValue) + " " + levelName;
121+
Color color = rel.getRelColor();
122+
123+
LabelAPI label = Global.getSettings().createLabel(line, Fonts.VICTOR_10);
124+
label.setColor(color);
125+
labels.add(label);
126+
}
127+
128+
for (int i = 0; i < labels.size(); i++) {
129+
LabelAPI label = labels.get(i);
130+
float w = label.computeTextWidth(label.getText());
131+
PositionAPI pos = label.getPosition();
132+
if (i == 0) {
133+
pos.inTR(X_PAD, Y_PAD);
134+
} else {
135+
float y = Y_PAD + i * LINE_HEIGHT;
136+
pos.setLocation(screenW - X_PAD - w, screenH - y - LINE_HEIGHT);
137+
}
138+
label.render(1f);
139+
}
140+
}
141+
142+
private static String formatRepValue(float rel) {
143+
int pct = (int) Math.round(rel * 100f);
144+
if (pct >= 0) {
145+
return "+" + pct;
146+
}
147+
return String.valueOf(pct);
148+
}
149+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"maxFactions": 15
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"id": "factionrelationships",
3+
"name": "Faction Relationships",
4+
"author": "boop",
5+
"version": "1.0.0",
6+
"description": "Shows a list of factions and their relationship with the player on the main navigation screen.",
7+
"gameVersion": "0.98a-RC8",
8+
"jars": ["jars/FactionRelationships.jar"],
9+
"modPlugin": "com.factionrelationships.FactionRelationshipsPlugin"
10+
}

0 commit comments

Comments
 (0)