feat(match3): Verbesserung der Fall-Logik und Auffüllung leerer Felder
- Optimierung der Fall-Logik für Tiles, um sicherzustellen, dass leere Positionen korrekt gefüllt werden. - Einführung einer neuen Methode zur Überprüfung und Auffüllung leerer gültiger Felder nach dem Fallen von Tiles. - Anpassungen an der Animation und den Debug-Ausgaben zur besseren Nachverfolgbarkeit der Fall- und Auffüllprozesse. - Verbesserung der Logik zur Handhabung von Tiles und deren Positionen im Spiel.
This commit is contained in:
185
DEPLOYMENT.md
Normal file
185
DEPLOYMENT.md
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
# YourPart Deployment Anleitung
|
||||||
|
|
||||||
|
Diese Anleitung beschreibt, wie Sie die YourPart-Anwendung auf einem Ubuntu 22.04 Server deployen.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- Ubuntu 22.04 Server
|
||||||
|
- Node.js 18+ installiert
|
||||||
|
- MySQL/MariaDB installiert und konfiguriert
|
||||||
|
- Redis installiert
|
||||||
|
- Apache2 installiert
|
||||||
|
- SSL-Zertifikate von Let's Encrypt (bereits vorhanden)
|
||||||
|
|
||||||
|
## Installation der Abhängigkeiten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Node.js installieren
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||||
|
sudo apt-get install -y nodejs
|
||||||
|
|
||||||
|
# MySQL installieren
|
||||||
|
sudo apt install mysql-server
|
||||||
|
|
||||||
|
# Redis installieren
|
||||||
|
sudo apt install redis-server
|
||||||
|
|
||||||
|
# Apache2 installieren
|
||||||
|
sudo apt install apache2
|
||||||
|
|
||||||
|
# Apache-Module aktivieren
|
||||||
|
sudo a2enmod proxy
|
||||||
|
sudo a2enmod proxy_http
|
||||||
|
sudo a2enmod proxy_wstunnel
|
||||||
|
sudo a2enmod rewrite
|
||||||
|
sudo a2enmod ssl
|
||||||
|
```
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
### 1. Datenbank einrichten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mysql_secure_installation
|
||||||
|
sudo mysql -u root -p
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE DATABASE yourpart CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
CREATE USER 'yourpart'@'localhost' IDENTIFIED BY 'your_secure_password';
|
||||||
|
GRANT ALL PRIVILEGES ON yourpart.* TO 'yourpart'@'localhost';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
EXIT;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Redis konfigurieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/redis/redis.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
Stellen Sie sicher, dass Redis auf localhost läuft und ein Passwort gesetzt ist.
|
||||||
|
|
||||||
|
### 3. Umgebungsvariablen konfigurieren
|
||||||
|
|
||||||
|
Erstellen Sie eine `.env`-Datei im Backend-Verzeichnis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Wichtige Variablen:
|
||||||
|
```env
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=2020
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_USER=yourpart
|
||||||
|
DB_PASS=your_secure_password
|
||||||
|
DB_NAME=yourpart
|
||||||
|
REDIS_HOST=localhost
|
||||||
|
REDIS_PASS=your_redis_password
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### 1. Skripte ausführbar machen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x deploy.sh deploy-backend.sh build-frontend.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Deployment ausführen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Skript wird automatisch:
|
||||||
|
- Das Frontend bauen
|
||||||
|
- Den Backend-Service installieren
|
||||||
|
- Die Apache-Konfiguration einrichten
|
||||||
|
- Alle Services starten
|
||||||
|
|
||||||
|
## Verifizierung
|
||||||
|
|
||||||
|
### 1. Service-Status prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status yourpart.service
|
||||||
|
sudo systemctl status apache2
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Logs überprüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backend-Logs
|
||||||
|
sudo journalctl -u yourpart.service -f
|
||||||
|
|
||||||
|
# Apache-Logs
|
||||||
|
sudo tail -f /var/log/apache2/yourpart.*.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Anwendung testen
|
||||||
|
|
||||||
|
Öffnen Sie in Ihrem Browser:
|
||||||
|
- https://www.your-part.de
|
||||||
|
|
||||||
|
## Wartung
|
||||||
|
|
||||||
|
### Service neu starten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl restart yourpart.service
|
||||||
|
sudo systemctl reload apache2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updates deployen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull origin main
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logs rotieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo logrotate -f /etc/logrotate.d/apache2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Backend startet nicht
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo journalctl -u yourpart.service -n 50
|
||||||
|
```
|
||||||
|
|
||||||
|
Prüfen Sie:
|
||||||
|
- Datenbankverbindung
|
||||||
|
- Redis-Verbindung
|
||||||
|
- Port 2020 ist verfügbar
|
||||||
|
- Berechtigungen in `/opt/yourpart/backend`
|
||||||
|
|
||||||
|
### Apache-Fehler
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apache2ctl configtest
|
||||||
|
sudo tail -f /var/log/apache2/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### SSL-Probleme
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo certbot certificates
|
||||||
|
sudo certbot renew --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sicherheit
|
||||||
|
|
||||||
|
- Firewall konfigurieren (nur Port 80, 443, 22 öffnen)
|
||||||
|
- Regelmäßige Updates
|
||||||
|
- Datenbank-Backups
|
||||||
|
- SSL-Zertifikate erneuern
|
||||||
|
- Logs überwachen
|
||||||
26
build-frontend.sh
Normal file
26
build-frontend.sh
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Building YourPart Frontend..."
|
||||||
|
|
||||||
|
# Zum Frontend-Verzeichnis wechseln
|
||||||
|
cd frontend
|
||||||
|
|
||||||
|
# Dependencies installieren
|
||||||
|
echo "Installing dependencies..."
|
||||||
|
npm ci --production
|
||||||
|
|
||||||
|
# Frontend bauen
|
||||||
|
echo "Building frontend..."
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Build-Verzeichnis nach /opt/yourpart kopieren
|
||||||
|
echo "Copying build to /opt/yourpart/frontend/dist..."
|
||||||
|
sudo mkdir -p /opt/yourpart/frontend
|
||||||
|
sudo cp -r dist /opt/yourpart/frontend/
|
||||||
|
|
||||||
|
# Berechtigungen setzen
|
||||||
|
echo "Setting permissions..."
|
||||||
|
sudo chown -R www-data:www-data /opt/yourpart/frontend
|
||||||
|
sudo chmod -R 755 /opt/yourpart/frontend
|
||||||
|
|
||||||
|
echo "Frontend build completed!"
|
||||||
30
deploy-backend.sh
Normal file
30
deploy-backend.sh
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Deploying YourPart Backend..."
|
||||||
|
|
||||||
|
# Zum Backend-Verzeichnis wechseln
|
||||||
|
cd backend
|
||||||
|
|
||||||
|
# Dependencies installieren
|
||||||
|
echo "Installing dependencies..."
|
||||||
|
npm ci --production
|
||||||
|
|
||||||
|
# Backend nach /opt/yourpart kopieren
|
||||||
|
echo "Copying backend to /opt/yourpart/backend..."
|
||||||
|
sudo mkdir -p /opt/yourpart/backend
|
||||||
|
sudo cp -r * /opt/yourpart/backend/
|
||||||
|
|
||||||
|
# Berechtigungen setzen
|
||||||
|
echo "Setting permissions..."
|
||||||
|
sudo chown -R www-data:www-data /opt/yourpart/backend
|
||||||
|
sudo chmod -R 755 /opt/yourpart/backend
|
||||||
|
|
||||||
|
# .env-Datei kopieren (falls vorhanden)
|
||||||
|
if [ -f .env ]; then
|
||||||
|
echo "Copying .env file..."
|
||||||
|
sudo cp .env /opt/yourpart/backend/
|
||||||
|
sudo chown www-data:www-data /opt/yourpart/backend/.env
|
||||||
|
sudo chmod 600 /opt/yourpart/backend/.env
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Backend deployment completed!"
|
||||||
87
deploy.sh
Normal file
87
deploy.sh
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "=== YourPart Deployment Script ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Prüfen ob wir im richtigen Verzeichnis sind
|
||||||
|
if [ ! -f "package.json" ]; then
|
||||||
|
echo "Error: Please run this script from the YourPart3 root directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prüfen ob sudo verfügbar ist
|
||||||
|
if ! command -v sudo &> /dev/null; then
|
||||||
|
echo "Error: sudo is required but not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verzeichnisstruktur erstellen
|
||||||
|
echo "Creating directory structure..."
|
||||||
|
sudo mkdir -p /opt/yourpart/{frontend,backend}
|
||||||
|
|
||||||
|
# Backend deployen
|
||||||
|
echo ""
|
||||||
|
echo "=== Deploying Backend ==="
|
||||||
|
./deploy-backend.sh
|
||||||
|
|
||||||
|
# Frontend bauen und deployen
|
||||||
|
echo ""
|
||||||
|
echo "=== Building and Deploying Frontend ==="
|
||||||
|
./build-frontend.sh
|
||||||
|
|
||||||
|
# Systemd Service installieren
|
||||||
|
echo ""
|
||||||
|
echo "=== Installing Systemd Service ==="
|
||||||
|
sudo cp yourpart.service /etc/systemd/system/
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable yourpart.service
|
||||||
|
|
||||||
|
# Apache-Konfiguration installieren
|
||||||
|
echo ""
|
||||||
|
echo "=== Installing Apache Configuration ==="
|
||||||
|
sudo cp yourpart-http.conf /etc/apache2/sites-available/yourpart-http.conf
|
||||||
|
sudo cp yourpart-https.conf /etc/apache2/sites-available/yourpart-https.conf
|
||||||
|
|
||||||
|
# Alte Konfiguration deaktivieren (falls vorhanden)
|
||||||
|
sudo a2dissite yourpart 2>/dev/null || true
|
||||||
|
|
||||||
|
# Neue Konfiguration aktivieren
|
||||||
|
sudo a2ensite yourpart-http
|
||||||
|
sudo a2ensite yourpart-https
|
||||||
|
|
||||||
|
# Apache-Module aktivieren
|
||||||
|
echo "Enabling required Apache modules..."
|
||||||
|
sudo a2enmod proxy
|
||||||
|
sudo a2enmod proxy_http
|
||||||
|
sudo a2enmod proxy_wstunnel
|
||||||
|
sudo a2enmod rewrite
|
||||||
|
sudo a2enmod ssl
|
||||||
|
|
||||||
|
# Apache neu laden
|
||||||
|
echo "Reloading Apache..."
|
||||||
|
sudo systemctl reload apache2
|
||||||
|
|
||||||
|
# Backend-Service starten
|
||||||
|
echo ""
|
||||||
|
echo "=== Starting Backend Service ==="
|
||||||
|
sudo systemctl start yourpart.service
|
||||||
|
|
||||||
|
# Status anzeigen
|
||||||
|
echo ""
|
||||||
|
echo "=== Deployment Status ==="
|
||||||
|
echo "Backend Service Status:"
|
||||||
|
sudo systemctl status yourpart.service --no-pager -l
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Apache Status:"
|
||||||
|
sudo systemctl status apache2 --no-pager -l
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Deployment Completed! ==="
|
||||||
|
echo "Your application should now be available at:"
|
||||||
|
echo " HTTP: http://your-part.de (redirects to HTTPS)"
|
||||||
|
echo " HTTPS: https://www.your-part.de"
|
||||||
|
echo ""
|
||||||
|
echo "To check logs:"
|
||||||
|
echo " Backend: sudo journalctl -u yourpart.service -f"
|
||||||
|
echo " Apache: sudo tail -f /var/log/apache2/yourpart.*.log"
|
||||||
@@ -293,18 +293,18 @@ export default {
|
|||||||
movesLeft: 15,
|
movesLeft: 15,
|
||||||
matchesMade: 0, // Neue: Zählt tatsächlich gemachte Matches
|
matchesMade: 0, // Neue: Zählt tatsächlich gemachte Matches
|
||||||
|
|
||||||
// Drag & drop
|
// Drag & drop
|
||||||
dragStartIndex: null,
|
dragStartIndex: null,
|
||||||
dragStartX: null,
|
dragStartX: null,
|
||||||
dragStartY: null,
|
dragStartY: null,
|
||||||
originalTilePosition: null,
|
originalTilePosition: null,
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
draggedTileIndex: null, // Neuer: Index des aktuell gedraggten Tiles
|
draggedTileIndex: null, // Neuer: Index des aktuell gedraggten Tiles
|
||||||
adjacentTilesForHover: [], // Neue: Liste der benachbarten Tiles für Hover
|
adjacentTilesForHover: [], // Neue: Liste der benachbarten Tiles für Hover
|
||||||
currentlyAnimatingTile: null, // Neuer: Index des aktuell animierten Tiles
|
currentlyAnimatingTile: null, // Neuer: Index des aktuell animierten Tiles
|
||||||
dragElement: null,
|
dragElement: null,
|
||||||
dragOffsetX: 0,
|
dragOffsetX: 0,
|
||||||
dragOffsetY: 0,
|
dragOffsetY: 0,
|
||||||
boundMouseMoveHandler: null,
|
boundMouseMoveHandler: null,
|
||||||
boundTouchMoveHandler: null,
|
boundTouchMoveHandler: null,
|
||||||
|
|
||||||
@@ -505,10 +505,10 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Neue Hilfsmethode ohne Rekursion
|
// Neue Hilfsmethode ohne Rekursion
|
||||||
loadLevelDataInternal(levelData) {
|
loadLevelDataInternal(levelData) {
|
||||||
return apiClient.get(`/api/match3/levels/${levelData.id}`)
|
return apiClient.get(`/api/match3/levels/${levelData.id}`)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
||||||
if (response.data && response.data.success && response.data.data) {
|
if (response.data && response.data.success && response.data.data) {
|
||||||
const freshLevelData = response.data.data;
|
const freshLevelData = response.data.data;
|
||||||
@@ -652,14 +652,14 @@ export default {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// Fallback: Setze currentLevel basierend auf completedLevels
|
// Fallback: Setze currentLevel basierend auf completedLevels
|
||||||
if (this.completedLevels > 0) {
|
if (this.completedLevels > 0) {
|
||||||
this.currentLevel = this.completedLevels + 1;
|
this.currentLevel = this.completedLevels + 1;
|
||||||
} else {
|
} else {
|
||||||
this.currentLevel = 1;
|
this.currentLevel = 1;
|
||||||
}
|
}
|
||||||
// Lade das Level basierend auf dem Fallback currentLevel
|
// Lade das Level basierend auf dem Fallback currentLevel
|
||||||
this.loadLevelData(this.currentLevel);
|
this.loadLevelData(this.currentLevel);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async initializeLevel() {
|
async initializeLevel() {
|
||||||
@@ -668,8 +668,8 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety check: ensure currentLevelData is loaded
|
// Safety check: ensure currentLevelData is loaded
|
||||||
if (!this.currentLevelData) {
|
if (!this.currentLevelData) {
|
||||||
// KEINE REKURSION: Lade Kampagnendaten nur einmal
|
// KEINE REKURSION: Lade Kampagnendaten nur einmal
|
||||||
this.loadCampaignData().then(async () => {
|
this.loadCampaignData().then(async () => {
|
||||||
// Nach dem Laden der Kampagne, initialisiere das Level direkt
|
// Nach dem Laden der Kampagne, initialisiere das Level direkt
|
||||||
@@ -789,7 +789,7 @@ export default {
|
|||||||
await this.checkBoardAfterSetup();
|
await this.checkBoardAfterSetup();
|
||||||
|
|
||||||
// WICHTIG: Setze das Spiel als aktiv, aber prüfe NICHT sofort die Level-Objekte
|
// WICHTIG: Setze das Spiel als aktiv, aber prüfe NICHT sofort die Level-Objekte
|
||||||
this.gameActive = true;
|
this.gameActive = true;
|
||||||
|
|
||||||
// KEINE Prüfung der Level-Objekte beim Start - diese werden nur nach Spielzügen geprüft
|
// KEINE Prüfung der Level-Objekte beim Start - diese werden nur nach Spielzügen geprüft
|
||||||
|
|
||||||
@@ -1107,7 +1107,7 @@ export default {
|
|||||||
const index = this.coordsToIndex(r, col);
|
const index = this.coordsToIndex(r, col);
|
||||||
if (index && board[index] && board[index].type === centerType && !this.isPowerUpTile(board[index].type)) {
|
if (index && board[index] && board[index].type === centerType && !this.isPowerUpTile(board[index].type)) {
|
||||||
verticalLength++;
|
verticalLength++;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1118,7 +1118,7 @@ export default {
|
|||||||
const index = this.coordsToIndex(row, c);
|
const index = this.coordsToIndex(row, c);
|
||||||
if (index && board[index] && board[index].type === centerType && !this.isPowerUpTile(board[index].type)) {
|
if (index && board[index] && board[index].type === centerType && !this.isPowerUpTile(board[index].type)) {
|
||||||
horizontalLength++;
|
horizontalLength++;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1408,9 +1408,9 @@ export default {
|
|||||||
|
|
||||||
// Prüfe auf 3er-Match
|
// Prüfe auf 3er-Match
|
||||||
if (row + 2 < this.boardHeight) {
|
if (row + 2 < this.boardHeight) {
|
||||||
const index1 = this.coordsToIndex(row, col);
|
const index1 = this.coordsToIndex(row, col);
|
||||||
const index2 = this.coordsToIndex(row + 1, col);
|
const index2 = this.coordsToIndex(row + 1, col);
|
||||||
const index3 = this.coordsToIndex(row + 2, col);
|
const index3 = this.coordsToIndex(row + 2, col);
|
||||||
|
|
||||||
// Prüfe ob alle drei Positionen bereits Teil eines höherwertigen Matches sind
|
// Prüfe ob alle drei Positionen bereits Teil eines höherwertigen Matches sind
|
||||||
if (!usedIndices.has(index1) && !usedIndices.has(index2) && !usedIndices.has(index3) &&
|
if (!usedIndices.has(index1) && !usedIndices.has(index2) && !usedIndices.has(index3) &&
|
||||||
@@ -1679,7 +1679,7 @@ export default {
|
|||||||
document.removeEventListener('mousemove', this.boundMouseMoveHandler);
|
document.removeEventListener('mousemove', this.boundMouseMoveHandler);
|
||||||
this.boundMouseMoveHandler = null;
|
this.boundMouseMoveHandler = null;
|
||||||
}
|
}
|
||||||
if (this.boundTouchMoveHandler) {
|
if (this.boundTouchMoveHandler) {
|
||||||
document.removeEventListener('touchmove', this.boundTouchMoveHandler);
|
document.removeEventListener('touchmove', this.boundTouchMoveHandler);
|
||||||
this.boundTouchMoveHandler = null;
|
this.boundTouchMoveHandler = null;
|
||||||
}
|
}
|
||||||
@@ -1758,11 +1758,11 @@ export default {
|
|||||||
this.moves--;
|
this.moves--;
|
||||||
this.movesLeft++;
|
this.movesLeft++;
|
||||||
|
|
||||||
// Wichtig: Auch ohne Matches Level-Objekte prüfen
|
// Wichtig: Auch ohne Matches Level-Objekte prüfen
|
||||||
// (falls der Spieler bereits alle Ziele erreicht hat)
|
// (falls der Spieler bereits alle Ziele erreicht hat)
|
||||||
// Nur prüfen wenn der Spieler bereits gespielt hat UND das Level nicht initialisiert wird
|
// Nur prüfen wenn der Spieler bereits gespielt hat UND das Level nicht initialisiert wird
|
||||||
if (this.moves > 0 && !this.isInitializingLevel) {
|
if (this.moves > 0 && !this.isInitializingLevel) {
|
||||||
this.checkLevelObjectives();
|
this.checkLevelObjectives();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1864,7 +1864,7 @@ export default {
|
|||||||
|
|
||||||
// WICHTIG: Erhöhe den Match-Zähler für Level-Objekte
|
// WICHTIG: Erhöhe den Match-Zähler für Level-Objekte
|
||||||
if (isPlayerMove && !this.isInitializingLevel) {
|
if (isPlayerMove && !this.isInitializingLevel) {
|
||||||
this.matchesMade += 1;
|
this.matchesMade += 1;
|
||||||
console.log(`🎯 Match-Zähler erhöht: ${this.matchesMade} Matches gemacht`);
|
console.log(`🎯 Match-Zähler erhöht: ${this.matchesMade} Matches gemacht`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1969,8 +1969,8 @@ export default {
|
|||||||
console.log('🔧 Debug: Alle Power-ups nach dem Fall-Down:');
|
console.log('🔧 Debug: Alle Power-ups nach dem Fall-Down:');
|
||||||
this.debugPowerUps();
|
this.debugPowerUps();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
// Debug: Zeige alle Power-ups nach dem Füllen
|
// Debug: Zeige alle Power-ups nach dem Füllen
|
||||||
console.log('🔧 Debug: Alle Power-ups nach dem Füllen:');
|
console.log('🔧 Debug: Alle Power-ups nach dem Füllen:');
|
||||||
@@ -2003,7 +2003,7 @@ export default {
|
|||||||
// WICHTIG: Prüfe Level-Objekte nach dem Verarbeiten der Matches
|
// WICHTIG: Prüfe Level-Objekte nach dem Verarbeiten der Matches
|
||||||
if (isPlayerMove && !this.isInitializingLevel) {
|
if (isPlayerMove && !this.isInitializingLevel) {
|
||||||
console.log('🎯 Prüfe Level-Objekte nach Match-Verarbeitung...');
|
console.log('🎯 Prüfe Level-Objekte nach Match-Verarbeitung...');
|
||||||
this.checkLevelObjectives();
|
this.checkLevelObjectives();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2015,94 +2015,127 @@ export default {
|
|||||||
|
|
||||||
let hasChanges = true;
|
let hasChanges = true;
|
||||||
let iteration = 0;
|
let iteration = 0;
|
||||||
|
const maxIterations = 10; // Verhindert Endlosschleifen
|
||||||
|
|
||||||
// Wiederhole bis keine weiteren Änderungen mehr auftreten
|
while (hasChanges && iteration < maxIterations) {
|
||||||
while (hasChanges && iteration < this.boardHeight) {
|
|
||||||
hasChanges = false;
|
|
||||||
iteration++;
|
iteration++;
|
||||||
|
console.log(`🔧 Fall-Down Iteration ${iteration}...`);
|
||||||
|
|
||||||
console.log(`🔧 Fall-Down Iteration ${iteration}`);
|
hasChanges = false;
|
||||||
|
|
||||||
// Sammle alle Tiles, die fallen sollen
|
// 1. Von unten nach oben leere Felder finden und Tiles nach unten verschieben
|
||||||
const tilesToFall = [];
|
|
||||||
|
|
||||||
// Gehe von unten nach oben durch jede Spalte
|
|
||||||
for (let col = 0; col < this.boardWidth; col++) {
|
for (let col = 0; col < this.boardWidth; col++) {
|
||||||
for (let row = this.boardHeight - 2; row >= 0; row--) { // Von vorletzter Zeile nach oben
|
console.log(`🔧 Prüfe Spalte ${col}...`);
|
||||||
const currentIndex = this.coordsToIndex(row, col);
|
|
||||||
const belowIndex = this.coordsToIndex(row + 1, col);
|
|
||||||
|
|
||||||
// Wenn aktuelles Tile existiert und das darunter leer ist
|
// Finde alle leeren Positionen in dieser Spalte von unten nach oben
|
||||||
if (this.board[currentIndex] && !this.board[belowIndex] && !this.isPowerUpTile(this.board[currentIndex].type)) {
|
for (let row = this.boardHeight - 1; row >= 0; row--) {
|
||||||
// Prüfe, ob das Zielfeld im board_layout gültig ist (nicht 'o')
|
const index = this.coordsToIndex(row, col);
|
||||||
const targetRow = row + 1;
|
|
||||||
const targetCol = col;
|
|
||||||
|
|
||||||
// Hole das board_layout für das aktuelle Level
|
// Wenn Position leer ist, prüfe ob sie im Layout gültig ist
|
||||||
|
if (!this.board[index]) {
|
||||||
if (this.currentLevelData && this.currentLevelData.boardLayout) {
|
if (this.currentLevelData && this.currentLevelData.boardLayout) {
|
||||||
const layout = this.currentLevelData.boardLayout;
|
const layoutRows = this.currentLevelData.boardLayout.split('\n');
|
||||||
const layoutRows = layout.split('\n');
|
if (row < layoutRows.length && col < layoutRows[row].length) {
|
||||||
|
const targetChar = layoutRows[row][col];
|
||||||
// Prüfe, ob das Zielfeld im Layout gültig ist
|
if (targetChar !== 'x') {
|
||||||
if (targetRow < layoutRows.length && targetCol < layoutRows[targetRow].length) {
|
console.log(`🔧 Position [${row}, ${col}] ist ungültig im Layout (${targetChar}) - überspringe`);
|
||||||
const targetChar = layoutRows[targetRow][targetCol];
|
continue; // Überspringe ungültige Positionen
|
||||||
|
|
||||||
// Nur fallen lassen, wenn das Zielfeld 'x' ist (gültig)
|
|
||||||
if (targetChar === 'x') {
|
|
||||||
tilesToFall.push({
|
|
||||||
fromIndex: currentIndex,
|
|
||||||
toIndex: belowIndex,
|
|
||||||
fromRow: row,
|
|
||||||
toRow: row + 1,
|
|
||||||
col: col
|
|
||||||
});
|
|
||||||
|
|
||||||
hasChanges = true;
|
|
||||||
} else {
|
|
||||||
console.log(`🔧 Tile kann nicht auf Position [${targetRow}, ${targetCol}] fallen - Layout zeigt '${targetChar}'`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// Fallback: Wenn kein Layout vorhanden, normale Logik verwenden
|
|
||||||
tilesToFall.push({
|
|
||||||
fromIndex: currentIndex,
|
|
||||||
toIndex: belowIndex,
|
|
||||||
fromRow: row,
|
|
||||||
toRow: row + 1,
|
|
||||||
col: col
|
|
||||||
});
|
|
||||||
|
|
||||||
hasChanges = true;
|
console.log(`🔧 Leere Position gefunden: [${row}, ${col}] -> Index ${index}`);
|
||||||
|
|
||||||
|
// Suche nach oben nach einem Tile
|
||||||
|
let tileFound = false;
|
||||||
|
for (let searchRow = row - 1; searchRow >= 0; searchRow--) {
|
||||||
|
const searchIndex = this.coordsToIndex(searchRow, col);
|
||||||
|
|
||||||
|
if (this.board[searchIndex] && !this.isPowerUpTile(this.board[searchIndex].type)) {
|
||||||
|
console.log(`🔧 Tile ${this.board[searchIndex].type} gefunden an [${searchRow}, ${col}] -> verschiebe nach [${row}, ${col}]`);
|
||||||
|
|
||||||
|
// Verschiebe Tile nach unten
|
||||||
|
this.board[index] = this.board[searchIndex];
|
||||||
|
this.board[searchIndex] = null;
|
||||||
|
|
||||||
|
// Aktualisiere DOM
|
||||||
|
this.$forceUpdate();
|
||||||
|
|
||||||
|
// Warte kurz für Animation
|
||||||
|
await this.wait(500);
|
||||||
|
|
||||||
|
hasChanges = true;
|
||||||
|
tileFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tileFound) {
|
||||||
|
console.log(`🔧 Kein Tile über Position [${row}, ${col}] gefunden`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Führe Fall-Animation für alle Tiles aus
|
// 2. Oberste Zeile nach fehlenden Feldern untersuchen und auffüllen
|
||||||
if (tilesToFall.length > 0) {
|
if (hasChanges) {
|
||||||
console.log(`🔧 ${tilesToFall.length} Tiles fallen in Iteration ${iteration}`);
|
console.log('🔧 Fülle oberste Zeile auf...');
|
||||||
|
|
||||||
// Führe Fall-Animation aus, BEVOR die Tiles im Board verschoben werden
|
for (let col = 0; col < this.boardWidth; col++) {
|
||||||
await this.animateTilesFalling(tilesToFall);
|
const index = this.coordsToIndex(0, col);
|
||||||
|
|
||||||
// Bewege Tiles im Board NACH der Animation
|
// Wenn oberste Position leer ist, prüfe ob sie im Layout gültig ist
|
||||||
tilesToFall.forEach(fallData => {
|
if (!this.board[index]) {
|
||||||
this.board[fallData.toIndex] = this.board[fallData.fromIndex];
|
if (this.currentLevelData && this.currentLevelData.boardLayout) {
|
||||||
this.board[fallData.fromIndex] = null;
|
const layoutRows = this.currentLevelData.boardLayout.split('\n');
|
||||||
});
|
if (0 < layoutRows.length && col < layoutRows[0].length) {
|
||||||
|
const targetChar = layoutRows[0][col];
|
||||||
|
if (targetChar !== 'x') {
|
||||||
|
console.log(`🔧 Oberste Position [0, ${col}] ist ungültig im Layout (${targetChar}) - überspringe`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Aktualisiere die Anzeige nach dem Fallen
|
// Erstelle neues Tile
|
||||||
|
const newTile = this.createRandomTile();
|
||||||
|
this.board[index] = newTile;
|
||||||
|
console.log(`🔧 Neues Tile ${newTile.type} an oberster Position [0, ${col}] hinzugefügt`);
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aktualisiere DOM nach dem Auffüllen
|
||||||
this.$forceUpdate();
|
this.$forceUpdate();
|
||||||
|
await this.wait(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kürzere Pause zwischen den Iterationen für bessere Performance
|
console.log(`🔧 Iteration ${iteration} abgeschlossen - Änderungen: ${hasChanges}`);
|
||||||
await this.wait(50);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`🔧 Fall-Down abgeschlossen nach ${iteration} Iterationen`);
|
if (iteration >= maxIterations) {
|
||||||
|
console.log('⚠️ Maximale Anzahl von Fall-Down Iterationen erreicht');
|
||||||
|
}
|
||||||
|
|
||||||
// Nach dem Fallen: Prüfe ob alle gültigen Felder ein Tile enthalten
|
console.log('🔧 Fall-Down-Logik abgeschlossen');
|
||||||
await this.checkAndFillEmptyValidFields();
|
},
|
||||||
|
|
||||||
|
// Hilfsfunktion: Zeige den aktuellen Board-Zustand in der Konsole
|
||||||
|
printBoardState() {
|
||||||
|
console.log('🔧 Board-Zustand:');
|
||||||
|
for (let row = 0; row < this.boardHeight; row++) {
|
||||||
|
let rowStr = '';
|
||||||
|
for (let col = 0; col < this.boardWidth; col++) {
|
||||||
|
const index = this.coordsToIndex(row, col);
|
||||||
|
const tile = this.board[index];
|
||||||
|
if (tile) {
|
||||||
|
rowStr += `[${tile.type}] `;
|
||||||
|
} else {
|
||||||
|
rowStr += '[ ] ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(` Zeile ${row}: ${rowStr}`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere Positionen mit neuen Tiles auf
|
||||||
@@ -2458,34 +2491,28 @@ export default {
|
|||||||
console.log(`🎬 Schrumpf-Animation abgeschlossen`);
|
console.log(`🎬 Schrumpf-Animation abgeschlossen`);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Animierte Fall-Animation für Tiles
|
// Animierte Fall-Animation für Tiles (einfache Animation nach dem Verschieben im Board)
|
||||||
async animateTilesFalling(tilesToFall) {
|
async animateTilesFalling(tilesToFall) {
|
||||||
console.log(`🎬 Starte Fall-Animation für ${tilesToFall.length} Tiles...`);
|
console.log(`🎬 Starte Fall-Animation für ${tilesToFall.length} Tiles...`);
|
||||||
|
|
||||||
// Sammle alle DOM-Elemente der fallenden Tiles (an ihren ursprünglichen Positionen)
|
// Sammle alle DOM-Elemente der fallenden Tiles (an ihren neuen Positionen)
|
||||||
const tileElements = tilesToFall.map(fallData => {
|
const tileElements = tilesToFall.map(fallData => {
|
||||||
const element = document.querySelector(`[data-index="${fallData.fromIndex}"]`);
|
const element = document.querySelector(`[data-index="${fallData.toIndex}"]`);
|
||||||
if (element) {
|
if (element) {
|
||||||
// Berechne die Fall-Distanz (sollte immer 1 Zeile sein)
|
// Berechne die Fall-Distanz
|
||||||
const fallDistance = fallData.toRow - fallData.fromRow;
|
const fallDistance = fallData.fallDistance || (fallData.toRow - fallData.fromRow);
|
||||||
if (fallDistance !== 1) {
|
|
||||||
console.warn(`⚠️ Unerwartete Fall-Distanz: ${fallDistance} Zeilen für Tile ${fallData.fromIndex}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tileHeight = 60; // Höhe eines Tiles in Pixeln
|
const tileHeight = 60; // Höhe eines Tiles in Pixeln
|
||||||
const fallPixels = fallDistance * tileHeight;
|
const fallPixels = fallDistance * tileHeight;
|
||||||
|
|
||||||
// Setze das Tile an seine ursprüngliche Position (oben)
|
// Setze das Tile an seine ursprüngliche Position (oben) mit transform
|
||||||
element.style.transform = `translateY(0px)`;
|
element.style.transform = `translateY(-${fallPixels}px)`;
|
||||||
element.style.transition = 'transform 0.3s ease-out';
|
element.style.transition = 'transform 0.4s ease-out';
|
||||||
|
|
||||||
// Füge CSS-Klasse für die Fall-Animation hinzu
|
// Füge CSS-Klasse für die Fall-Animation hinzu
|
||||||
element.classList.add('falling');
|
element.classList.add('falling');
|
||||||
|
|
||||||
// Speichere die Fall-Pixel für später
|
console.log(`🎬 Fall-Animation für Tile ${fallData.toIndex}: ${fallDistance} Zeile(n) (${fallPixels}px)`);
|
||||||
element.dataset.fallPixels = fallPixels;
|
|
||||||
|
|
||||||
console.log(`🎬 Fall-Animation für Tile ${fallData.fromIndex}: ${fallDistance} Zeile(n) (${fallPixels}px)`);
|
|
||||||
}
|
}
|
||||||
return element;
|
return element;
|
||||||
}).filter(element => element !== null);
|
}).filter(element => element !== null);
|
||||||
@@ -2500,17 +2527,16 @@ export default {
|
|||||||
// Warte kurz, damit die transform-Eigenschaft gesetzt wird
|
// Warte kurz, damit die transform-Eigenschaft gesetzt wird
|
||||||
await this.wait(50);
|
await this.wait(50);
|
||||||
|
|
||||||
// Bewege alle Tiles nach unten (Fall-Animation)
|
// Bewege alle Tiles zu ihrer finalen Position (Fall-Animation)
|
||||||
tileElements.forEach(element => {
|
tileElements.forEach(element => {
|
||||||
const fallPixels = parseInt(element.dataset.fallPixels);
|
element.style.transform = 'translateY(0px)';
|
||||||
element.style.transform = `translateY(${fallPixels}px)`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Spiele Fall-Sound ab
|
// Spiele Fall-Sound ab
|
||||||
this.playSound('falling');
|
this.playSound('falling');
|
||||||
|
|
||||||
// Warte auf die Fall-Animation (0,3 Sekunden)
|
// Warte auf die Fall-Animation (0,4 Sekunden)
|
||||||
await this.wait(300);
|
await this.wait(400);
|
||||||
|
|
||||||
// Entferne die CSS-Klassen und transform-Eigenschaften
|
// Entferne die CSS-Klassen und transform-Eigenschaften
|
||||||
tileElements.forEach(element => {
|
tileElements.forEach(element => {
|
||||||
@@ -2749,8 +2775,8 @@ export default {
|
|||||||
// Führe Fall-Down-Logik aus
|
// Führe Fall-Down-Logik aus
|
||||||
await this.fallTilesDown();
|
await this.fallTilesDown();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
console.log('🔧 Fall-Prozess abgeschlossen');
|
console.log('🔧 Fall-Prozess abgeschlossen');
|
||||||
},
|
},
|
||||||
@@ -2916,8 +2942,8 @@ export default {
|
|||||||
// Führe Fall-Down-Logik aus
|
// Führe Fall-Down-Logik aus
|
||||||
await this.fallTilesDown();
|
await this.fallTilesDown();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
// Erhöhe den Zug-Zähler
|
// Erhöhe den Zug-Zähler
|
||||||
this.countPowerUpMove();
|
this.countPowerUpMove();
|
||||||
@@ -2961,8 +2987,8 @@ export default {
|
|||||||
// Führe Fall-Down-Logik aus
|
// Führe Fall-Down-Logik aus
|
||||||
await this.fallTilesDown();
|
await this.fallTilesDown();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
// Erhöhe den Zug-Zähler
|
// Erhöhe den Zug-Zähler
|
||||||
this.countPowerUpMove();
|
this.countPowerUpMove();
|
||||||
@@ -3026,8 +3052,8 @@ export default {
|
|||||||
// Führe Fall-Down-Logik aus
|
// Führe Fall-Down-Logik aus
|
||||||
await this.fallTilesDown();
|
await this.fallTilesDown();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
// Erhöhe den Zug-Zähler
|
// Erhöhe den Zug-Zähler
|
||||||
this.countPowerUpMove();
|
this.countPowerUpMove();
|
||||||
@@ -3090,8 +3116,8 @@ export default {
|
|||||||
// Führe Fall-Down-Logik aus
|
// Führe Fall-Down-Logik aus
|
||||||
await this.fallTilesDown();
|
await this.fallTilesDown();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
// Erhöhe den Zug-Zähler
|
// Erhöhe den Zug-Zähler
|
||||||
this.countPowerUpMove();
|
this.countPowerUpMove();
|
||||||
@@ -3643,7 +3669,7 @@ export default {
|
|||||||
draggedElement.style.transition = 'all 0.3s ease-out';
|
draggedElement.style.transition = 'all 0.3s ease-out';
|
||||||
|
|
||||||
// Warte kurz und setze dann alle Styles komplett zurück
|
// Warte kurz und setze dann alle Styles komplett zurück
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
draggedElement.style.transition = '';
|
draggedElement.style.transition = '';
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
@@ -4781,8 +4807,8 @@ export default {
|
|||||||
// Führe Fall-Down-Logik aus
|
// Führe Fall-Down-Logik aus
|
||||||
await this.fallTilesDown();
|
await this.fallTilesDown();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
// Erhöhe den Zug-Zähler
|
// Erhöhe den Zug-Zähler
|
||||||
this.countPowerUpMove();
|
this.countPowerUpMove();
|
||||||
@@ -4918,8 +4944,8 @@ export default {
|
|||||||
// Führe Fall-Down-Logik aus
|
// Führe Fall-Down-Logik aus
|
||||||
await this.fallTilesDown();
|
await this.fallTilesDown();
|
||||||
|
|
||||||
// Fülle leere Positionen mit neuen Tiles auf
|
// Fülle leere gültige Felder mit neuen Tiles auf
|
||||||
await this.fillEmptyPositions();
|
await this.checkAndFillEmptyValidFields();
|
||||||
|
|
||||||
// WICHTIG: Zug-Zähler wird bereits in handleRainbowSwap erhöht, nicht hier nochmal!
|
// WICHTIG: Zug-Zähler wird bereits in handleRainbowSwap erhöht, nicht hier nochmal!
|
||||||
// this.countPowerUpMove(); // ENTFERNT - wird bereits in handleRainbowSwap aufgerufen
|
// this.countPowerUpMove(); // ENTFERNT - wird bereits in handleRainbowSwap aufgerufen
|
||||||
|
|||||||
56
rollback.sh
Normal file
56
rollback.sh
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "=== YourPart Rollback Script ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Bestätigung anfordern
|
||||||
|
read -p "Are you sure you want to rollback? This will stop the new service and restore the old configuration. (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Rollback cancelled."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Starting rollback process..."
|
||||||
|
|
||||||
|
# Neuen Service stoppen und deaktivieren
|
||||||
|
echo "Stopping new YourPart service..."
|
||||||
|
sudo systemctl stop yourpart.service
|
||||||
|
sudo systemctl disable yourpart.service
|
||||||
|
|
||||||
|
# Alte Apache-Konfiguration wiederherstellen
|
||||||
|
echo "Restoring old Apache configuration..."
|
||||||
|
|
||||||
|
# Neue Konfigurationen deaktivieren
|
||||||
|
sudo a2dissite yourpart-http
|
||||||
|
sudo a2dissite yourpart-https
|
||||||
|
|
||||||
|
# Alte Konfiguration wieder aktivieren (falls vorhanden)
|
||||||
|
if [ -f "/etc/apache2/sites-available/yourpart" ]; then
|
||||||
|
echo "Re-enabling old configuration..."
|
||||||
|
sudo a2ensite yourpart
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apache neu laden
|
||||||
|
echo "Reloading Apache..."
|
||||||
|
sudo systemctl reload apache2
|
||||||
|
|
||||||
|
# Neue Dateien entfernen
|
||||||
|
echo "Removing new files..."
|
||||||
|
sudo rm -rf /opt/yourpart/backend
|
||||||
|
sudo rm -rf /opt/yourpart/frontend
|
||||||
|
sudo rm -f /etc/systemd/system/yourpart.service
|
||||||
|
sudo rm -f /etc/apache2/sites-available/yourpart-http.conf
|
||||||
|
sudo rm -f /etc/apache2/sites-available/yourpart-https.conf
|
||||||
|
|
||||||
|
# Systemd neu laden
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Rollback Completed ==="
|
||||||
|
echo "The old configuration has been restored."
|
||||||
|
echo ""
|
||||||
|
echo "To verify:"
|
||||||
|
echo " - Check if the old service is running on port 2030"
|
||||||
|
echo " - Check Apache status: sudo systemctl status apache2"
|
||||||
|
echo " - Check if the old site is accessible"
|
||||||
40
yourpart-http.conf
Normal file
40
yourpart-http.conf
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<VirtualHost your-part.de:80>
|
||||||
|
ServerAdmin webmaster@your-part.de
|
||||||
|
ServerName your-part.de
|
||||||
|
ServerAlias www.your-part.de
|
||||||
|
|
||||||
|
DocumentRoot /opt/yourpart/frontend/dist
|
||||||
|
|
||||||
|
DirectoryIndex index.html
|
||||||
|
|
||||||
|
# Frontend statische Dateien
|
||||||
|
<Directory "/opt/yourpart/frontend/dist">
|
||||||
|
AllowOverride None
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
Require all granted
|
||||||
|
|
||||||
|
# Fallback für Vue Router
|
||||||
|
FallbackResource /index.html
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
# API-Requests an Backend weiterleiten
|
||||||
|
ProxyPass "/api/" "http://localhost:2020/api/"
|
||||||
|
ProxyPassReverse "/api/" "http://localhost:2020/api/"
|
||||||
|
|
||||||
|
# WebSocket-Requests an Backend weiterleiten
|
||||||
|
ProxyPass "/socket.io/" "http://localhost:2020/socket.io/"
|
||||||
|
ProxyPassReverse "/socket.io/" "http://localhost:2020/socket.io/"
|
||||||
|
|
||||||
|
ErrorLog /var/log/apache2/yourpart.error.log
|
||||||
|
CustomLog /var/log/apache2/yourpart.access.log combined
|
||||||
|
|
||||||
|
HostnameLookups Off
|
||||||
|
UseCanonicalName Off
|
||||||
|
ServerSignature On
|
||||||
|
|
||||||
|
# SSL Redirect
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteCond %{SERVER_NAME} =www.your-part.de [OR]
|
||||||
|
RewriteCond %{SERVER_NAME} =your-part.de
|
||||||
|
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
|
||||||
|
</VirtualHost>
|
||||||
46
yourpart-https.conf
Normal file
46
yourpart-https.conf
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<IfModule mod_ssl.c>
|
||||||
|
<VirtualHost your-part.de:443>
|
||||||
|
ServerAdmin webmaster@your-part.de
|
||||||
|
ServerName your-part.de
|
||||||
|
ServerAlias www.your-part.de
|
||||||
|
|
||||||
|
DocumentRoot /opt/yourpart/frontend/dist
|
||||||
|
|
||||||
|
DirectoryIndex index.html
|
||||||
|
|
||||||
|
# Frontend statische Dateien
|
||||||
|
<Directory "/opt/yourpart/frontend/dist">
|
||||||
|
AllowOverride None
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
Require all granted
|
||||||
|
|
||||||
|
# Fallback für Vue Router
|
||||||
|
FallbackResource /index.html
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
# API-Requests an Backend weiterleiten
|
||||||
|
ProxyPass "/api/" "http://localhost:2020/api/"
|
||||||
|
ProxyPassReverse "/api/" "http://localhost:2020/api/"
|
||||||
|
|
||||||
|
# WebSocket-Requests an Backend weiterleiten
|
||||||
|
ProxyPass "/socket.io/" "http://localhost:2020/socket.io/"
|
||||||
|
ProxyPassReverse "/socket.io/" "http://localhost:2020/socket.io/"
|
||||||
|
|
||||||
|
ErrorLog /var/log/apache2/yourpart.error.log
|
||||||
|
CustomLog /var/log/apache2/yourpart.access.log combined
|
||||||
|
|
||||||
|
HostnameLookups Off
|
||||||
|
UseCanonicalName Off
|
||||||
|
ServerSignature On
|
||||||
|
|
||||||
|
# SSL-Konfiguration
|
||||||
|
Include /etc/letsencrypt/options-ssl-apache.conf
|
||||||
|
SSLCertificateFile /etc/letsencrypt/live/www.your-part.de/fullchain.pem
|
||||||
|
SSLCertificateKeyFile /etc/letsencrypt/live/www.your-part.de/privkey.pem
|
||||||
|
|
||||||
|
# www Redirect
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteCond %{SERVER_NAME} =your-part.de
|
||||||
|
RewriteRule ^ https://www.%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
|
||||||
|
</VirtualHost>
|
||||||
|
</IfModule>
|
||||||
22
yourpart.service
Normal file
22
yourpart.service
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=YourPart Backend Server
|
||||||
|
After=network.target mysql.service redis-server.service
|
||||||
|
Wants=mysql.service redis-server.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=www-data
|
||||||
|
Group=www-data
|
||||||
|
WorkingDirectory=/opt/yourpart/backend
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
Environment=PORT=2020
|
||||||
|
ExecStart=/usr/bin/node server.js
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
SyslogIdentifier=yourpart-backend
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Reference in New Issue
Block a user