Update server/src/index.js

This commit is contained in:
2025-11-13 15:47:42 +00:00
parent 35a89bf5ad
commit 8009a57273

View File

@@ -7,7 +7,7 @@ import http from 'http';
import { Server as IOServer } from 'socket.io';
import jwt from 'jsonwebtoken';
import { init as dbInit, Users, Characters, Inventory, query } from './db.js';
import { init as dbInit, Characters, Inventory, query } from './db.js';
const app = express();
app.use(helmet());
@@ -15,15 +15,15 @@ app.use(cors({ origin: true, credentials: true }));
app.use(express.json());
app.use(cookieParser());
// simple world config
const WORLD = {
width: 4000,
height: 3000,
gatherRange: 40
};
// ===== Auth helpers =====
const COOKIE = 'auth';
// JWT payload: { cid: characterId }
function signToken(cid) {
return jwt.sign({ cid }, process.env.JWT_SECRET, { expiresIn: '30d' });
}
@@ -32,7 +32,7 @@ function authFromReq(req) {
try {
const token = req.cookies?.[COOKIE];
if (!token) return null;
return jwt.verify(token, process.env.JWT_SECRET); // { cid, iat, exp }
return jwt.verify(token, process.env.JWT_SECRET);
} catch {
return null;
}
@@ -40,7 +40,7 @@ function authFromReq(req) {
// ===== HTTP API =====
// Register a new character with username + password
// Register: username+password per character
app.post('/api/register', async (req, res) => {
const { username, password } = req.body || {};
if (!username || !password) {
@@ -59,7 +59,7 @@ app.post('/api/register', async (req, res) => {
}
});
// Login as a specific character
// Login: per-character
app.post('/api/login', async (req, res) => {
const { username, password } = req.body || {};
if (!username || !password) {
@@ -75,12 +75,12 @@ app.post('/api/login', async (req, res) => {
.json({ ok: true });
});
// Logout: clear cookie
// Logout
app.post('/api/logout', (req, res) => {
res.clearCookie(COOKIE).json({ ok: true });
});
// Current character + inventory
// Current character
app.get('/api/me', async (req, res) => {
const auth = authFromReq(req);
if (!auth) return res.status(401).json({ error: 'Not logged in' });
@@ -92,8 +92,7 @@ app.get('/api/me', async (req, res) => {
res.json({ character: ch, inventory: inv, world: WORLD });
});
// static client
// Serve client
app.use(express.static(new URL('../static', import.meta.url).pathname));
const server = http.createServer(app);
@@ -101,13 +100,14 @@ const io = new IOServer(server, {
cors: { origin: true, credentials: true }
});
// ===== In-memory world =====
// ===== World: resource nodes =====
let nodes = [];
function spawnNodes() {
nodes = [];
const types = ['wood', 'stone', 'ore', 'fiber'];
for (let i = 0; i < 120; i++) {
const types = ['wood', 'stone', 'ore', 'fiber'];
const type = types[i % types.length];
nodes.push({
id: i,
@@ -119,19 +119,23 @@ function spawnNodes() {
});
}
}
spawnNodes();
// socket player info (very simple)
const socketsToPlayers = new Map(); // socket.id -> { x,y,name,uid,charId }
// socket.id -> player state
const socketsToPlayers = new Map(); // { x,y,name,cid,charId }
// ===== Socket.IO =====
io.on('connection', socket => {
// character auth from cookie
socket.on('auth:join', async ack => {
try {
const cookieHeader = socket.handshake.headers.cookie || '';
const match = cookieHeader.match(/auth=([^;]+)/);
if (!match) return ack?.({ error: 'no auth cookie' });
const token = match[1];
const token = decodeURIComponent(match[1]);
const decoded = jwt.verify(token, process.env.JWT_SECRET); // { cid }
const ch = await Characters.getById(decoded.cid);
@@ -148,7 +152,7 @@ io.on('connection', socket => {
socket.join('world');
// Send initial nodes in same handler or from separate listener
// send initial nodes
socket.emit(
'nodes:init',
nodes.map(n => ({
@@ -171,10 +175,10 @@ io.on('connection', socket => {
}
});
// very basic server-side movement (trusting client target)
socket.on('move:click', target => {
const p = socketsToPlayers.get(socket.id);
if (!p) return;
// for now, we just trust and update directly (you can add validation later)
p.x = Math.max(0, Math.min(WORLD.width, target.x));
p.y = Math.max(0, Math.min(WORLD.height, target.y));
});
@@ -182,6 +186,7 @@ io.on('connection', socket => {
socket.on('gather', async ({ nodeId }, ack) => {
const p = socketsToPlayers.get(socket.id);
if (!p) return ack?.({ error: 'not authed' });
const node = nodes.find(n => n.id === nodeId);
if (!node || !node.alive) return ack?.({ error: 'invalid node' });
@@ -216,7 +221,7 @@ io.on('connection', socket => {
});
});
// game loop: respawn nodes + broadcast simple state
// game loop: respawn nodes + broadcast positions
setInterval(() => {
const now = Date.now();
for (const n of nodes) {
@@ -226,7 +231,6 @@ setInterval(() => {
}
}
// player snapshot
const players = [];
for (const [id, p] of socketsToPlayers) {
players.push({ id, name: p.name, x: p.x, y: p.y });