Una economia integrada entre Twitch, Discord y Minecraft crea un ciclo de engagement donde los viewers tienen razon para ver el stream, unirse al Discord y jugar en el servidor. Esta guia explica como disenar e implementar ese sistema: moneda unificada, conversiones, base de datos central y sincronizacion en tiempo real.
FUENTES de monedas:
Twitch Watch Time (10 pts / hora de stream)
Channel Points redeems (ganas pts al ver)
Discord actividad (5 pts / mensaje, max 50/dia)
Votos en server lists (100 pts / voto)
Suscripcion Twitch (500 pts / mes)
Bits (1 bit = 0.1 pts)
USOS de monedas:
Tienda en Discord (roles, badges, cosmeticos)
Tienda en MC (items, rangos temporales, efectos)
Apuestas en stream (predicciones Twitch)
Channel Points premium (redeems exclusivos)La clave es que los jugadores acumulan monedas haciendo lo que ya hacen: ver el stream, chatear en Discord, votar. Y pueden gastarlas donde quieran dentro del ecosistema.
-- Tabla principal de usuarios
CREATE TABLE community_users (
id INTEGER PRIMARY KEY,
discord_id TEXT UNIQUE,
twitch_name TEXT UNIQUE,
mc_uuid TEXT UNIQUE,
balance INTEGER DEFAULT 0,
total_earned INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Historial de transacciones
CREATE TABLE transactions (
id INTEGER PRIMARY KEY,
user_id INTEGER REFERENCES community_users(id),
amount INTEGER, -- positivo = ganado, negativo = gastado
source TEXT, -- 'twitch_watch', 'discord_msg', 'mc_vote', 'purchase', etc.
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);// Dar puntos por watch time usando Twitch EventSub
// Cada vez que el viewer envia un chatmessage, actualizamos su ultima actividad
// Cada 10 minutos, damos puntos a todos los viewers activos
import { EventSubWsListener } from '@twurple/eventsub-ws';
const activeViewers = new Map(); // twitch_name -> ultimo_mensaje_timestamp
listener.onChannelChatMessage(channelId, async (e) => {
activeViewers.set(e.chatterUserName, Date.now());
});
// Cada 10 minutos, dar puntos de watch time
setInterval(async () => {
const now = Date.now();
for (const [viewer, lastSeen] of activeViewers) {
if (now - lastSeen < 15 * 60 * 1000) { // activo en ultimos 15 min
await addPoints(viewer, 'twitch', 10, 'watch_time');
} else {
activeViewers.delete(viewer); // limpiar inactivos
}
}
}, 10 * 60 * 1000);// Comando /tienda para ver y comprar items
const STORE_ITEMS = [
{ id: 'vip7', name: 'Rango VIP 7 dias (MC)', cost: 500, type: 'mc_rank' },
{ id: 'badge_og', name: 'Badge OG Discord', cost: 1000, type: 'discord_role' },
{ id: 'spawn_effect', name: 'Efecto de spawn unico (MC)', cost: 300, type: 'mc_cosmetic' },
{ id: 'color_nick', name: 'Nick de color en Discord', cost: 200, type: 'discord_role' },
];
// Al comprar, descontar balance y aplicar el reward correspondiente
async function purchase(userId, itemId) {
const item = STORE_ITEMS.find(i => i.id === itemId);
const balance = await getBalance(userId);
if (balance < item.cost) throw new Error('Saldo insuficiente');
await deductPoints(userId, item.cost, compra_);
await applyReward(userId, item);
}async function applyReward(userId, item) {
const user = await db.get('SELECT * FROM community_users WHERE id = ?', userId);
if (!user.mc_uuid) return; // no tiene cuenta MC vinculada
const mcName = await getMCNameFromUUID(user.mc_uuid);
switch (item.type) {
case 'mc_rank':
await rcon.send(lp user parent add vip);
await rcon.send(lp user meta addtempgroup vip 7d);
break;
case 'mc_cosmetic':
await rcon.send(cosmetics set spawn_effect rainbow);
break;
}
}Nuestra comunidad tiene moneda unificada Twitch+Discord+MC. Conecta y participa.
Ver Hosting