Skip to content

Commit 4230aca

Browse files
Merge branch 'main' into wayland-screenshots
2 parents 10a76af + c511c18 commit 4230aca

25 files changed

+456
-72
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
# SC Trade Companion
2+
## 1.0.4
3+
### Other
4+
- Read location from game logs
5+
- *You can set your LIVE game path through a new setting*
6+
- *You should still select the location in the dropdown when taking screenshots*
7+
- Improve performance and security
8+
9+
## 1.0.3
10+
### Other
11+
- Handle 3.24 kiosk layout
12+
- Improve character recognition accuracy
13+
214
## 1.0.2
315
### Other
416
- Improve text-reading accuracy

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ group = 'tools.sctrade'
88
version = '1.0.4'
99

1010
java {
11-
sourceCompatibility = '17'
11+
sourceCompatibility = '21'
1212
}
1313

1414
repositories {

src/main/java/tools/sctrade/companion/domain/commodity/CommodityListing.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,19 @@
33
import java.time.Instant;
44

55
public record CommodityListing(String location, TransactionType transactionType, String commodity,
6-
double price, int inventory, InventoryLevel inventoryLevel, String batchId, Instant timestamp) {
6+
Double price, Integer inventory, InventoryLevel inventoryLevel, Integer maxBoxSize,
7+
String batchId, Instant timestamp) {
8+
public CommodityListing(String location, TransactionType transactionType, String commodity,
9+
double price, int inventory, InventoryLevel inventoryLevel, String batchId,
10+
Instant timestamp) {
11+
this(location, transactionType, commodity, price, inventory, inventoryLevel, null, batchId,
12+
timestamp);
13+
}
14+
15+
public CommodityListing(String location, TransactionType transactionType, String commodity,
16+
Integer maxBoxSize, String batchId, Instant timestamp) {
17+
this(location, transactionType, commodity, null, null, null, maxBoxSize, batchId, timestamp);
18+
}
719

820
public CommodityListing withLocation(String location) {
921
return new CommodityListing(location, transactionType(), commodity(), price(), inventory(),

src/main/java/tools/sctrade/companion/domain/commodity/CommodityListingFactory.java

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.Collections;
99
import java.util.Iterator;
1010
import java.util.List;
11+
import java.util.Locale;
1112
import java.util.Optional;
1213
import java.util.TreeMap;
1314
import org.slf4j.Logger;
@@ -40,6 +41,16 @@ public CommodityListingFactory(CommodityRepository commodityRepository, ImageWri
4041
.withInitial(() -> new CommodityListingsTesseractOcr(preprocessingManipulations));
4142
}
4243

44+
public CommodityListing build(String shopId, String shopName, String commodity,
45+
int maxBoxSizeInScu) {
46+
Instant now = TimeUtil.getNow();
47+
String location = String.format(Locale.ROOT, "%s#%s", shopName, shopId);
48+
String batchId = HashUtil.hash(String.format(Locale.ROOT, "%s%s%d%s", location, commodity,
49+
maxBoxSizeInScu, now.toString()));
50+
return new CommodityListing(location, TransactionType.SELLS, commodity, maxBoxSizeInScu,
51+
batchId, now);
52+
}
53+
4354
public Collection<CommodityListing> build(BufferedImage screenCapture, String location) {
4455
try {
4556
logger.debug("Reading listings...");

src/main/java/tools/sctrade/companion/domain/commodity/CommodityService.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Collection;
55
import java.util.Optional;
66
import java.util.concurrent.Semaphore;
7+
import java.util.concurrent.TimeUnit;
78
import org.slf4j.Logger;
89
import org.slf4j.LoggerFactory;
910
import org.springframework.scheduling.annotation.Scheduled;
@@ -32,11 +33,21 @@ public CommodityService(CommoditySubmissionFactory submissionFactory,
3233
this.pendingSubmission = Optional.empty();
3334
}
3435

36+
public void process(CommodityListing commodityListing) throws InterruptedException {
37+
CommoditySubmission submission = submissionFactory.build(commodityListing);
38+
39+
process(submission);
40+
}
41+
3542
@Override
3643
public void process(BufferedImage screenCapture) throws InterruptedException {
3744
CommoditySubmission submission = submissionFactory.build(screenCapture);
3845
notificationService.info(LocalizationUtil.get("infoCommodityListingsRead"));
3946

47+
process(submission);
48+
}
49+
50+
private void process(CommoditySubmission submission) throws InterruptedException {
4051
try {
4152
logger.debug("Acquiring mutex...");
4253
mutex.acquire();
@@ -52,7 +63,7 @@ public void process(BufferedImage screenCapture) throws InterruptedException {
5263
}
5364
}
5465

55-
@Scheduled(fixedDelay = 600)
66+
@Scheduled(fixedDelay = 30, timeUnit = TimeUnit.SECONDS)
5667
public void flush() throws InterruptedException {
5768
try {
5869
logger.debug("Acquiring mutex...");

src/main/java/tools/sctrade/companion/domain/commodity/CommoditySubmissionFactory.java

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tools.sctrade.companion.domain.commodity;
22

33
import java.awt.image.BufferedImage;
4+
import java.util.List;
45
import org.slf4j.Logger;
56
import org.slf4j.LoggerFactory;
67
import tools.sctrade.companion.domain.notification.NotificationService;
@@ -40,4 +41,8 @@ CommoditySubmission build(BufferedImage screenCapture) {
4041

4142
return new CommoditySubmission(userService.get(), listings);
4243
}
44+
45+
CommoditySubmission build(CommodityListing commodityListing) {
46+
return new CommoditySubmission(userService.get(), List.of(commodityListing));
47+
}
4348
}

src/main/java/tools/sctrade/companion/domain/gamelog/FilePathObserver.java

-17
This file was deleted.

src/main/java/tools/sctrade/companion/domain/gamelog/FilePathSubject.java

-27
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package tools.sctrade.companion.domain.gamelog;
2+
3+
import tools.sctrade.companion.utils.patterns.ChainOfResponsability;
4+
5+
public abstract class GameLogLineProcessor extends ChainOfResponsability<String> {
6+
7+
protected String regex;
8+
9+
@Override
10+
protected boolean canHandle(String value) {
11+
return value.matches(regex);
12+
}
13+
}

src/main/java/tools/sctrade/companion/domain/gamelog/GameLogListener.java

-10
This file was deleted.

src/main/java/tools/sctrade/companion/domain/gamelog/GameLogPathSubject.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import org.slf4j.LoggerFactory;
88
import tools.sctrade.companion.domain.setting.Setting;
99
import tools.sctrade.companion.domain.setting.SettingRepository;
10+
import tools.sctrade.companion.utils.patterns.Subject;
1011

11-
public class GameLogPathSubject extends FilePathSubject {
12+
public class GameLogPathSubject extends Subject<Path> {
1213
static final String GAME_LOG_FILE = "Game.log";
1314

1415
private final Logger logger = LoggerFactory.getLogger(GameLogPathSubject.class);
@@ -19,7 +20,6 @@ public GameLogPathSubject(SettingRepository settings) {
1920
super();
2021
this.settings = settings;
2122
this.observers = new ArrayList<>();
22-
setState();
2323
}
2424

2525
public void setStarCitizenLivePath(String starCitizenLivePath) {
@@ -34,7 +34,7 @@ public void setStarCitizenLivePath(String starCitizenLivePath) {
3434
}
3535

3636
public Optional<String> getStarCitizenLivePath() {
37-
return Optional.ofNullable(settings.get(Setting.STAR_CITIZEN_LIVE_PATH).toString());
37+
return Optional.ofNullable(settings.get(Setting.STAR_CITIZEN_LIVE_PATH));
3838
}
3939

4040
@Override
@@ -43,7 +43,7 @@ protected void setState() {
4343
return;
4444
}
4545

46-
filePath = Path.of(getStarCitizenLivePath().get(), GAME_LOG_FILE);
46+
state = Path.of(getStarCitizenLivePath().get(), GAME_LOG_FILE);
4747
notifyObservers();
4848
}
4949
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package tools.sctrade.companion.domain.gamelog.lineprocessors;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
import tools.sctrade.companion.utils.patterns.ChainOfResponsability;
6+
7+
public class FallbackLogLineProcessor extends ChainOfResponsability<String> {
8+
private final Logger logger = LoggerFactory.getLogger(FallbackLogLineProcessor.class);
9+
10+
@Override
11+
protected boolean canHandle(String value) {
12+
return true;
13+
}
14+
15+
@Override
16+
protected void handle(String value) {
17+
logger.trace("No chain link could handle '{}'", value);
18+
}
19+
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package tools.sctrade.companion.domain.gamelog.lineprocessors;
2+
3+
import java.util.Locale;
4+
import java.util.regex.Pattern;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import tools.sctrade.companion.domain.commodity.CommodityListingFactory;
8+
import tools.sctrade.companion.domain.commodity.CommodityService;
9+
import tools.sctrade.companion.domain.gamelog.GameLogLineProcessor;
10+
import tools.sctrade.companion.domain.notification.NotificationService;
11+
import tools.sctrade.companion.utils.LocalizationUtil;
12+
13+
public class LoadShopInventoryDataLogLineProcessor extends GameLogLineProcessor {
14+
private final Logger logger =
15+
LoggerFactory.getLogger(LoadShopInventoryDataLogLineProcessor.class);
16+
17+
private NotificationService notificationService;
18+
private CommodityListingFactory commodityListingFactory;
19+
private CommodityService commodityService;
20+
21+
public LoadShopInventoryDataLogLineProcessor(CommodityListingFactory commodityListingFactory,
22+
CommodityService commodityService, NotificationService notificationService) {
23+
this.regex =
24+
".+LoadShopInventoryData.+shopId\\[(?<shopId>\\d+)\\] shopName\\[(?<shopName>[\\w-]+)\\] commodityName\\[ResourceType\\.(?<commodityName>[\\w-]+)\\].+boxSize\\[(?<maxBoxSize>\\d+)\\] \\[Team_NAPU\\]\\[Shops\\]\\[UI\\]";
25+
this.commodityListingFactory = commodityListingFactory;
26+
this.commodityService = commodityService;
27+
this.notificationService = notificationService;
28+
}
29+
30+
@Override
31+
protected void handle(String value) {
32+
var pattern = Pattern.compile(regex);
33+
var matcher = pattern.matcher(value);
34+
matcher.matches();
35+
36+
var shopId = matcher.group("shopId");
37+
var shopName = matcher.group("shopName");
38+
var commodityName = matcher.group("commodityName");
39+
var maxBoxSize = Integer.valueOf(matcher.group("maxBoxSize"));
40+
41+
logger.info("Shop {}#{} sells {} in boxes of up to {} SCU", shopName, shopId, commodityName,
42+
maxBoxSize);
43+
notificationService
44+
.info(String.format(Locale.ROOT, LocalizationUtil.get("infoLocationDetectedFromLogs"),
45+
String.format(Locale.ROOT, "%s#%s", shopName, shopId)));
46+
47+
var commodityListing =
48+
commodityListingFactory.build(shopId, shopName, commodityName, maxBoxSize);
49+
50+
try {
51+
commodityService.process(commodityListing);
52+
} catch (InterruptedException e) {
53+
logger.error("Could not send {} for processing", commodityListing, e);
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package tools.sctrade.companion.domain.gamelog.lineprocessors;
2+
3+
import java.time.Instant;
4+
import java.time.LocalDateTime;
5+
import java.time.ZoneId;
6+
import java.time.format.DateTimeFormatter;
7+
import java.util.Locale;
8+
import java.util.regex.Pattern;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
import tools.sctrade.companion.utils.patterns.ChainOfResponsability;
12+
13+
public class OldLogLineProcessor extends ChainOfResponsability<String> {
14+
private static final DateTimeFormatter DATE_TIME_FORMATTER =
15+
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ROOT); // 2024-11-13T15:01:11.106Z
16+
17+
private final Logger logger = LoggerFactory.getLogger(OldLogLineProcessor.class);
18+
19+
private final Pattern pattern = Pattern.compile("^<(?<timestamp>.{24})> .+");
20+
private final Instant applicationOpenTime;
21+
22+
public OldLogLineProcessor() {
23+
this.applicationOpenTime = Instant.now();
24+
}
25+
26+
@Override
27+
protected boolean canHandle(String value) {
28+
var matcher = pattern.matcher(value);
29+
30+
if (matcher.matches()) {
31+
var timestamp = matcher.group("timestamp");
32+
var timestampInstant =
33+
LocalDateTime.parse(timestamp, DATE_TIME_FORMATTER).atZone(ZoneId.of("UTC")).toInstant();
34+
35+
return timestampInstant.isBefore(applicationOpenTime);
36+
} else {
37+
return false;
38+
}
39+
}
40+
41+
@Override
42+
protected void handle(String value) {
43+
logger.trace("Old log line ignored: '{}'", value);
44+
}
45+
46+
}

src/main/java/tools/sctrade/companion/gui/SettingsTab.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ private void updateUsername() {
6363

6464
private void buildStarCitizenLivePathField(GameLogPathSubject gameLogService) {
6565
var starCitizenLivePathLabel = buildLabel(3, LocalizationUtil.get("labelStarCitizenLivePath"));
66-
var starCitizenLivePathField = buildTextField(3, gameLogService.getStarCitizenLivePath().get());
66+
var starCitizenLivePathField =
67+
buildTextField(3, gameLogService.getStarCitizenLivePath().orElse(null));
6768
starCitizenLivePathField.putClientProperty("JTextField.placeholderText",
6869
LocalizationUtil.get("textFieldStarCitizenLivePathPlaceholder"));
6970
starCitizenLivePathLabel.setLabelFor(starCitizenLivePathField);

0 commit comments

Comments
 (0)