Files
xxx-sphere-web/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameService.java
Mario ca0e933d95
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
Weiter am Taskgame gebastelt
2026-05-02 23:10:41 +02:00

209 lines
9.6 KiB
Java

package de.oaa.xxx.games.bdsm;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import de.oaa.xxx.games.bdsm.entity.BdsmGameEntity;
import de.oaa.xxx.games.bdsm.repository.AktiveSperreRepository;
import de.oaa.xxx.games.bdsm.repository.BdsmGameRepository;
import de.oaa.xxx.games.bdsm.repository.MitspielerRepository;
import de.oaa.xxx.games.chastity.cardlock.CardLockEntity;
import de.oaa.xxx.games.chastity.cardlock.CardlockRepository;
import de.oaa.xxx.games.history.GameHistoryEntity;
import de.oaa.xxx.games.history.GameHistoryRepository;
import de.oaa.xxx.games.history.GameRole;
import de.oaa.xxx.games.history.GameType;
import de.oaa.xxx.social.SystemMessageService;
import de.oaa.xxx.social.entity.MessageCause;
import de.oaa.xxx.user.UserRepository;
/**
* Service für komplexe BDSM-Game-Operationen.
* Kapselt Spielabschluss-Logik (XP-Vergabe, History) und den BDSM→Chastity-Übergang.
*/
@Service
public class BdsmGameService {
private static final Logger LOGGER = LoggerFactory.getLogger(BdsmGameService.class);
private final BdsmGameRepository sessionRepository;
private final MitspielerRepository mitspielerRepository;
private final AktiveSperreRepository aktiveSperreRepository;
private final UserRepository userRepository;
private final GameHistoryRepository gameHistoryRepository;
private final CardlockRepository cardlockRepository;
private final SystemMessageService systemMessageService;
public BdsmGameService(BdsmGameRepository sessionRepository,
MitspielerRepository mitspielerRepository,
AktiveSperreRepository aktiveSperreRepository,
UserRepository userRepository,
GameHistoryRepository gameHistoryRepository,
CardlockRepository cardlockRepository,
SystemMessageService systemMessageService) {
this.sessionRepository = sessionRepository;
this.mitspielerRepository = mitspielerRepository;
this.aktiveSperreRepository = aktiveSperreRepository;
this.userRepository = userRepository;
this.gameHistoryRepository = gameHistoryRepository;
this.cardlockRepository = cardlockRepository;
this.systemMessageService = systemMessageService;
}
/**
* Beendet eine BDSM-Session ordentlich: History speichern, XP vergeben,
* Gäste auf eigenem Gerät benachrichtigen, Daten aufräumen.
*/
@Transactional
public void spielAbschliessen(BdsmGameEntity entity) {
LocalDateTime endTime = LocalDateTime.now();
long durationMinutes = Duration.between(entity.getStartZeit(), endTime).toMinutes();
GameHistoryEntity entry = new GameHistoryEntity();
entry.setGameName("BDSM Game");
entry.setGameType(GameType.BDSM);
entry.setStartTime(entity.getStartZeit());
entry.setEndTime(endTime);
entry.setDurationMinutes(durationMinutes);
entry.addParticipant(entity.getUserId(), GameRole.PLAYER);
entity.getMitspieler().stream()
.filter(m -> m.getUserId() != null)
.forEach(m -> entry.addParticipant(m.getUserId(), GameRole.PLAYER));
gameHistoryRepository.save(entry);
int xp = (int) durationMinutes;
userRepository.findById(entity.getUserId()).ifPresent(u -> {
u.setBdsmXp(u.getBdsmXp() + xp);
userRepository.save(u);
});
entity.getMitspieler().stream()
.filter(m -> m.getUserId() != null)
.forEach(m -> userRepository.findById(m.getUserId()).ifPresent(u -> {
u.setBdsmXp(u.getBdsmXp() + xp);
userRepository.save(u);
}));
// Gäste auf eigenem Gerät benachrichtigen
String endNachricht = "Das BDSM-Spiel wurde erfolgreich beendet. Danke fürs Mitspielen! 🎉";
entity.getMitspieler().stream()
.filter(m -> m.isEigenesGeraet() && m.getUserId() != null)
.forEach(m -> systemMessageService.send(entity.getUserId(), m.getUserId(),
endNachricht, "/userhome.html", MessageCause.GAME_STATE));
bereinige(entity);
}
/**
* Überführt eine BDSM-Session in ein neues Chastity-Lock (BDSM→Chastity-Transition).
* History + XP werden wie beim normalen Spielabschluss vergeben.
*
* @return Das neu angelegte CardLockEntity
* @throws IllegalArgumentException wenn Session oder Template nicht gefunden
* @throws IllegalStateException wenn Lockee bereits ein aktives Lock hat
*/
@Transactional
public CardLockEntity zuChastity(UUID sessionId, UUID templateLockId, UUID lockeeUserId, UUID keyholderUserId) {
BdsmGameEntity entity = sessionRepository.findById(sessionId)
.orElseThrow(() -> new IllegalArgumentException("Session nicht gefunden: " + sessionId));
CardLockEntity template = cardlockRepository.findById(templateLockId)
.orElseThrow(() -> new IllegalArgumentException("Template-Lock nicht gefunden: " + templateLockId));
if (lockeeUserId != null
&& cardlockRepository.existsByLockeeAndStartTimeIsNotNullAndUnlockTimeIsNull(lockeeUserId)) {
throw new IllegalStateException("Lockee hat bereits ein aktives Chastity-Lock");
}
LocalDateTime now = LocalDateTime.now();
CardLockEntity newLock = new CardLockEntity();
newLock.setName(template.getName());
newLock.setLockee(lockeeUserId);
newLock.setKeyholder(keyholderUserId);
newLock.setInitialCards(template.getInitialCards());
newLock.setPickEverySeconds(template.getPickEverySeconds());
newLock.setAccumulatePicks(template.isAccumulatePicks());
newLock.setShowRemainingCards(template.isShowRemainingCards());
newLock.setLatestOpeningtime(template.getLatestOpeningtime());
newLock.setHygineOpeningDurationSeconds(template.getHygineOpeningDurationSeconds());
newLock.setHygineOpeningEverySeconds(template.getHygineOpeningEverySeconds());
newLock.setTasks(template.getTasks());
newLock.setRequiresVerification(template.isRequiresVerification());
newLock.setTestLock(false);
newLock.setTaskMode(template.getTaskMode());
int codeLines = template.getUnlockCodeLength() != null ? template.getUnlockCodeLength() : 5;
newLock.setUnlockCodeLength(codeLines);
StringBuilder codeBuilder = new StringBuilder();
java.util.Random rng = new java.util.Random();
for (int i = 0; i < codeLines; i++) codeBuilder.append(rng.nextInt(10));
newLock.setUnlockCode(codeBuilder.toString());
newLock.setStartTime(now);
newLock.setAvailableCards(template.getInitialCards() != null
? new ArrayList<>(template.getInitialCards()) : new ArrayList<>());
newLock.setOpenPicks(0);
if (template.getPickEverySeconds() != null) {
newLock.setNextCardIn(now.plusSeconds(template.getPickEverySeconds()));
}
if (template.getHygineOpeningEverySeconds() != null) {
newLock.setLastHygineOpening(now);
}
cardlockRepository.save(newLock);
// Lockee benachrichtigen
if (lockeeUserId != null) {
userRepository.findById(keyholderUserId).ifPresent(keyholder ->
systemMessageService.send(keyholderUserId, lockeeUserId,
keyholder.getName() + " hat nach dem BDSM Game ein Chastity Lock auf dich gesetzt.",
"/games/chastity/activelock.html", MessageCause.GAME_STATE));
}
// Spielabschluss-Logik (History + XP + Cleanup)
LocalDateTime endTime = LocalDateTime.now();
long durationMinutes = Duration.between(entity.getStartZeit(), endTime).toMinutes();
GameHistoryEntity entry = new GameHistoryEntity();
entry.setGameName("BDSM Game");
entry.setGameType(GameType.BDSM);
entry.setStartTime(entity.getStartZeit());
entry.setEndTime(endTime);
entry.setDurationMinutes(durationMinutes);
entry.addParticipant(entity.getUserId(), GameRole.PLAYER);
entity.getMitspieler().stream()
.filter(m -> m.getUserId() != null)
.forEach(m -> entry.addParticipant(m.getUserId(), GameRole.PLAYER));
gameHistoryRepository.save(entry);
int xp = (int) durationMinutes;
userRepository.findById(entity.getUserId()).ifPresent(u -> {
u.setBdsmXp(u.getBdsmXp() + xp);
userRepository.save(u);
});
entity.getMitspieler().stream()
.filter(m -> m.getUserId() != null)
.forEach(m -> userRepository.findById(m.getUserId()).ifPresent(u -> {
u.setBdsmXp(u.getBdsmXp() + xp);
userRepository.save(u);
}));
bereinige(entity);
LOGGER.info("BDSM-Session {} in Chastity-Lock {} überführt (Lockee: {}, Keyholder: {})",
sessionId, newLock.getLockId(), lockeeUserId, keyholderUserId);
return newLock;
}
/** Löscht alle Session-Daten (Sperren, Mitspieler, Session selbst). */
private void bereinige(BdsmGameEntity entity) {
aktiveSperreRepository.deleteAll(entity.getAktiveSperren());
mitspielerRepository.deleteAll(entity.getMitspieler());
sessionRepository.delete(entity);
}
}