Compare commits
2 Commits
dbfd3537fe
...
79d0012d66
| Author | SHA1 | Date | |
|---|---|---|---|
| 79d0012d66 | |||
| 1dde34d266 |
@@ -7,3 +7,11 @@ Features:
|
||||
- match targets up with members that have the appropriate stats
|
||||
- dashboard to see who is supposed to hit who
|
||||
- maybe also enemy stats
|
||||
|
||||
|
||||
ToDo:
|
||||
- move interval button to a neutral spot
|
||||
- sections to list faction memebers
|
||||
- needs to be movable objects
|
||||
- Assignment pools depending on stats
|
||||
- players will be round-robin queued their targets from here
|
||||
BIN
__pycache__/config.cpython-311.pyc
Normal file
BIN
__pycache__/config.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/main.cpython-311.pyc
Normal file
BIN
__pycache__/main.cpython-311.pyc
Normal file
Binary file not shown.
BIN
cogs/__pycache__/assignments.cpython-311.pyc
Normal file
BIN
cogs/__pycache__/assignments.cpython-311.pyc
Normal file
Binary file not shown.
BIN
cogs/__pycache__/commands.cpython-311.pyc
Normal file
BIN
cogs/__pycache__/commands.cpython-311.pyc
Normal file
Binary file not shown.
68
main.py
68
main.py
@@ -4,10 +4,59 @@ from config import ALLOWED_CHANNEL_ID, HIT_CHECK_INTERVAL, REASSIGN_DELAY
|
||||
from cogs.assignments import Assignments
|
||||
from cogs.commands import HitCommands
|
||||
|
||||
import asyncio
|
||||
import uvicorn
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from pydantic import BaseModel
|
||||
|
||||
from services.torn_api import update_enemy_faction, update_friendly_faction
|
||||
|
||||
# -----------------------------
|
||||
# FastAPI setup
|
||||
# -----------------------------
|
||||
app = FastAPI()
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
# -----------------------------
|
||||
# Dashboard page
|
||||
# -----------------------------
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def dashboard(request: Request):
|
||||
print(">>> DASHBOARD ROUTE LOADED")
|
||||
return templates.TemplateResponse("dashboard.html", {"request": request})
|
||||
|
||||
# -----------------------------
|
||||
# Pydantic model for JSON payloads
|
||||
# -----------------------------
|
||||
class FactionRequest(BaseModel):
|
||||
faction_id: int
|
||||
interval: int
|
||||
|
||||
# -----------------------------
|
||||
# API Endpoints
|
||||
# -----------------------------
|
||||
@app.post("/api/update_enemy_faction")
|
||||
async def api_enemy(data: FactionRequest):
|
||||
await update_enemy_faction(data.faction_id, data.interval)
|
||||
return {"status": "enemy loop running", "id": data.faction_id, "interval": data.interval}
|
||||
|
||||
@app.post("/api/update_friendly_faction")
|
||||
async def api_friendly(data: FactionRequest):
|
||||
await update_friendly_faction(data.faction_id, data.interval)
|
||||
return {"status": "friendly loop running", "id": data.faction_id, "interval": data.interval}
|
||||
|
||||
# -----------------------------
|
||||
# Discord bot setup
|
||||
# -----------------------------
|
||||
intents = discord.Intents.default()
|
||||
intents.message_content = True
|
||||
|
||||
# Global state
|
||||
enrolled_attackers = []
|
||||
enemy_queue = []
|
||||
active_assignments = {}
|
||||
@@ -43,4 +92,19 @@ bot = HitDispatchBot(command_prefix="!", intents=intents)
|
||||
async def on_ready():
|
||||
print(f"Logged in as {bot.user.name}")
|
||||
|
||||
bot.run("MTQ0Mjg3NjU3NTUzMDg3NzAxMQ.GNuHPr.UreuYD1B7YYjfsbfRcEbhFyjyqvhQDepRCN4kk")
|
||||
TOKEN = "YOUR_DISCORD_TOKEN"
|
||||
|
||||
async def start_bot():
|
||||
await bot.start(TOKEN)
|
||||
|
||||
# -----------------------------
|
||||
# Main entry
|
||||
# -----------------------------
|
||||
if __name__ == "__main__":
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
# Start Discord bot in background
|
||||
loop.create_task(start_bot())
|
||||
|
||||
# Run FastAPI (this will keep the loop alive)
|
||||
uvicorn.run(app, host="127.0.0.1", port=8000)
|
||||
|
||||
BIN
services/__pycache__/ffscouter.cpython-311.pyc
Normal file
BIN
services/__pycache__/ffscouter.cpython-311.pyc
Normal file
Binary file not shown.
BIN
services/__pycache__/torn_api.cpython-311.pyc
Normal file
BIN
services/__pycache__/torn_api.cpython-311.pyc
Normal file
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
# services/torn_api.py
|
||||
import aiohttp
|
||||
import json
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
from config import TORN_API_KEY, ENEMY_FACTION_ID, YOUR_FACTION_ID
|
||||
from .ffscouter import fetch_batch_stats
|
||||
@@ -8,6 +9,13 @@ from .ffscouter import fetch_batch_stats
|
||||
ENEMY_FILE = Path("data/enemy_faction.json")
|
||||
FRIENDLY_FILE = Path("data/friendly_faction.json")
|
||||
|
||||
# Track running tasks + current faction IDs
|
||||
enemy_task = None
|
||||
friendly_task = None
|
||||
|
||||
current_enemy_id = None
|
||||
current_friendly_id = None
|
||||
|
||||
|
||||
async def fetch_and_save_faction(faction_id: int, file_path: Path) -> bool:
|
||||
"""
|
||||
@@ -59,10 +67,59 @@ async def fetch_and_save_faction(faction_id: int, file_path: Path) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
# Wrappers for clarity
|
||||
async def update_enemy_faction() -> bool:
|
||||
return await fetch_and_save_faction(ENEMY_FACTION_ID, ENEMY_FILE)
|
||||
|
||||
|
||||
async def update_friendly_faction() -> bool:
|
||||
return await fetch_and_save_faction(YOUR_FACTION_ID, FRIENDLY_FILE)
|
||||
#Loop for the constant update of members and the stop function
|
||||
|
||||
async def stop_task_if_running(task: asyncio.Task | None):
|
||||
"""Cancel an existing running task safely."""
|
||||
if task and not task.done():
|
||||
task.cancel()
|
||||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
async def faction_loop(faction_id: int, file_path: Path, interval: int):
|
||||
"""
|
||||
Runs fetch_and_save_faction() in a loop forever, waiting `interval`
|
||||
seconds between iterations.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
await fetch_and_save_faction(faction_id, file_path)
|
||||
except Exception as e:
|
||||
print(f"Error during faction loop for {faction_id}: {e}")
|
||||
|
||||
await asyncio.sleep(interval)
|
||||
|
||||
|
||||
|
||||
#Functions to call the loop, maybe add one to just call once?
|
||||
async def update_enemy_faction(new_faction_id: int, interval: int):
|
||||
global enemy_task, current_enemy_id
|
||||
|
||||
# If faction ID changes → stop old loop
|
||||
if new_faction_id != current_enemy_id:
|
||||
print(f"[ENEMY] Changing faction from {current_enemy_id} → {new_faction_id}")
|
||||
await stop_task_if_running(enemy_task)
|
||||
current_enemy_id = new_faction_id
|
||||
|
||||
# Start new loop
|
||||
enemy_task = asyncio.create_task(
|
||||
faction_loop(new_faction_id, ENEMY_FILE, interval)
|
||||
)
|
||||
|
||||
|
||||
async def update_friendly_faction(new_faction_id: int, interval: int):
|
||||
global friendly_task, current_friendly_id
|
||||
|
||||
if new_faction_id != current_friendly_id:
|
||||
print(f"[FRIENDLY] Changing faction from {current_friendly_id} → {new_faction_id}")
|
||||
await stop_task_if_running(friendly_task)
|
||||
current_friendly_id = new_faction_id
|
||||
|
||||
friendly_task = asyncio.create_task(
|
||||
faction_loop(new_faction_id, FRIENDLY_FILE, interval)
|
||||
)
|
||||
|
||||
|
||||
36
static/dashboard.js
Normal file
36
static/dashboard.js
Normal file
@@ -0,0 +1,36 @@
|
||||
async function updateEnemy() {
|
||||
const factionId = parseInt(document.getElementById("enemyId").value);
|
||||
const interval = parseInt(document.getElementById("refreshInterval").value);
|
||||
|
||||
if (!factionId || !interval) {
|
||||
alert("Please enter Enemy Faction ID and Refresh Interval!");
|
||||
return;
|
||||
}
|
||||
|
||||
await fetch(`/api/update_enemy_faction`, {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify({ faction_id: factionId, interval: interval })
|
||||
});
|
||||
}
|
||||
|
||||
async function updateFriendly() {
|
||||
const factionId = parseInt(document.getElementById("friendlyId").value);
|
||||
|
||||
if (!factionId) {
|
||||
alert("Please enter Friendly Faction ID!");
|
||||
return;
|
||||
}
|
||||
|
||||
const interval = parseInt(document.getElementById("refreshInterval").value);
|
||||
if (!interval) {
|
||||
alert("Please enter Refresh Interval!");
|
||||
return;
|
||||
}
|
||||
|
||||
await fetch(`/api/update_friendly_faction`, {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify({ faction_id: factionId, interval: interval })
|
||||
});
|
||||
}
|
||||
55
static/styles.css
Normal file
55
static/styles.css
Normal file
@@ -0,0 +1,55 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #1e1e2f;
|
||||
color: #f0f0f0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 2rem auto;
|
||||
padding: 2rem;
|
||||
background-color: #2c2c3e;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 0 20px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #ffcc00;
|
||||
}
|
||||
|
||||
.faction-section {
|
||||
background-color: #3a3a4d;
|
||||
margin: 1.5rem 0;
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.faction-section h2 {
|
||||
color: #66ccff;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
padding: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
background-color: #66ccff;
|
||||
color: #1e1e2f;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #3399ff;
|
||||
}
|
||||
28
templates/dashboard.html
Normal file
28
templates/dashboard.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>War Dashboard</title>
|
||||
<link rel="stylesheet" href="/static/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>War Dashboard</h1>
|
||||
|
||||
<div class="faction-section">
|
||||
<h2>Enemy Faction</h2>
|
||||
<input type="number" id="enemyId" placeholder="Enemy Faction ID">
|
||||
<input type="number" id="refreshInterval" placeholder="Refresh Interval (sec)">
|
||||
<button onclick="updateEnemy()">Refresh Enemy</button>
|
||||
</div>
|
||||
|
||||
<div class="faction-section">
|
||||
<h2>Friendly Faction</h2>
|
||||
<input type="number" id="friendlyId" placeholder="Friendly Faction ID">
|
||||
<button onclick="updateFriendly()">Refresh Friendly</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/dashboard.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user