Home / Developers / World of Warcraft
⚔️

World of Warcraft

C++ / Lua (Eluna) TrinityCore / AzerothCore

Overview

Reward your WoW private server players for voting on topgservers. This guide covers two approaches: a C++ core script for TrinityCore/AzerothCore, and a Lua Eluna script for easier deployment. Both poll the vote-check API and can grant gold, items, or custom rewards.

Prerequisites

  • A WoW private server running TrinityCore or AzerothCore
  • Eluna Lua engine (recommended) or C++ core compilation setup
  • topgservers API key — generate one in My Servers → API
  • Webhook secret (optional, for real-time rewards via a sidecar)
  • cURL development libraries (libcurl) if using C++ approach

Installation

1 Choose your approach

Eluna (Lua) is recommended for most servers — no recompilation needed. The C++ approach is for servers that need maximum performance or don't have Eluna.

Directory structure (Eluna)
lua_scripts/
└── topg_vote.lua

2 Create the Eluna script

Place the Lua script in your server's `lua_scripts/` directory. It will be loaded automatically on server start.

topg_vote.lua
-- topgservers Vote Checker for Eluna (TrinityCore / AzerothCore)
local API_KEY = "tgs_your_api_key_here"
local CHECK_INTERVAL = 60000 -- milliseconds
local REWARD_ITEM_ID = 29434 -- Badge of Justice (example)
local REWARD_COUNT = 5

local rewarded = {}

local function CheckVote(event, player)
    local name = player:GetName()
    if rewarded[name] then return end

    -- Eluna HTTP requires the HttpRequest module or
    -- an external vote-check script (see below)
end

3 Set up the external vote checker

Since Eluna has limited HTTP support, use a companion script that writes vote results to a file or database that the Lua script reads.

vote_checker.sh (cron every minute)
#!/bin/bash
# Cron: * * * * * /path/to/vote_checker.sh
API_KEY="tgs_your_api_key_here"
DB_NAME="world"
DB_USER="trinity"

# Get online character names from the database
PLAYERS=$(mysql -u$DB_USER -p -D characters -se   "SELECT name FROM characters WHERE online = 1")

for PLAYER in $PLAYERS; do
  RESPONSE=$(curl -s -H "Authorization: Bearer $API_KEY"     "https://topgservers.net/api/v1/vote-check?username=$PLAYER")

  VOTED=$(echo "$RESPONSE" | grep -o '"voted":true')
  if [ -n "$VOTED" ]; then
    # Insert into a custom votes table for the Lua script to read
    mysql -u$DB_USER -p -D $DB_NAME -e       "INSERT IGNORE INTO topg_votes (name, date) VALUES ('$PLAYER', CURDATE())"
  fi
done

Configuration

topg_vote.lua (config section)
-- Configuration
local CONFIG = {
    apiKey          = "tgs_your_api_key_here",
    webhookSecret   = "whsec_your_secret_here",
    checkInterval   = 60000,       -- ms between checks

    -- Rewards
    rewardItemId    = 29434,       -- Badge of Justice
    rewardCount     = 5,
    rewardGold      = 100,         -- gold (not copper)
    rewardMessage   = "Thanks for voting on topgservers!",
}

Vote Check

Call the /api/v1/vote-check endpoint to determine if a player has voted today.

topg_vote.lua — Eluna reward from DB
-- Read from the topg_votes table populated by the cron script
local function ProcessVotes(event, player)
    local name = player:GetName()
    local query = CharDBQuery(string.format(
        "SELECT 1 FROM topg_votes WHERE name = '%s' AND date = CURDATE() AND rewarded = 0",
        name
    ))

    if query then
        -- Mark as rewarded
        CharDBExecute(string.format(
            "UPDATE topg_votes SET rewarded = 1 WHERE name = '%s' AND date = CURDATE()",
            name
        ))
        GrantReward(player)
    end
end

-- Check on player login and periodically
RegisterPlayerEvent(3, ProcessVotes)  -- PLAYER_EVENT_ON_LOGIN

Webhook Receiver

Verify the X-TopG-Signature header using HMAC-SHA256 to ensure webhook payloads are authentic.

webhook_receiver.py (companion sidecar)
"""
Lightweight webhook receiver for WoW servers.
Run alongside your game server. Inserts into the topg_votes table
so the Eluna script can pick up rewards.
"""
import hmac, hashlib, json, mysql.connector
from http.server import HTTPServer, BaseHTTPRequestHandler

WEBHOOK_SECRET = "whsec_your_secret_here"
DB_CONFIG = {
    "host": "127.0.0.1",
    "user": "trinity",
    "password": "password",
    "database": "characters"
}

class WebhookHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers.get('Content-Length', 0))
        body = self.rfile.read(length).decode()
        sig = self.headers.get('X-TopG-Signature', '')

        if not verify_signature(body, sig):
            self.send_response(401)
            self.end_headers()
            return

        data = json.loads(body)
        username = data.get('username', '')

        if username:
            db = mysql.connector.connect(**DB_CONFIG)
            cursor = db.cursor()
            cursor.execute(
                "INSERT IGNORE INTO topg_votes (name, date) VALUES (%s, CURDATE())",
                (username,)
            )
            db.commit()
            db.close()

        self.send_response(200)
        self.end_headers()

def verify_signature(body, sig_header):
    parts = dict(p.split('=', 1) for p in sig_header.split(',') if '=' in p)
    timestamp = parts.get('t', '')
    received = parts.get('v1', '')

    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        f"{timestamp}.{body}".encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, received)

if __name__ == '__main__':
    server = HTTPServer(('0.0.0.0', 8090), WebhookHandler)
    print("Webhook receiver listening on :8090")
    server.serve_forever()

Reward Examples

Reward examples (Eluna)
function GrantReward(player)
    -- Give item (e.g., Badge of Justice x5)
    player:AddItem(CONFIG.rewardItemId, CONFIG.rewardCount)

    -- Give gold (in copper: 1 gold = 10000 copper)
    player:ModifyMoney(CONFIG.rewardGold * 10000)

    -- Send mail with item
    SendMail(
        "Vote Reward",                      -- subject
        "Thanks for voting on topgservers!", -- body
        player:GetGUIDLow(),                -- receiver
        0,                                  -- sender (0 = system)
        61,                                 -- stationery
        0,                                  -- delay
        0,                                  -- money
        0,                                  -- cod
        CONFIG.rewardItemId,                -- item entry
        CONFIG.rewardCount                  -- item count
    )

    player:SendBroadcastMessage(CONFIG.rewardMessage)
end

Notes & Tips

The hybrid approach (cron/sidecar + DB + Eluna) is battle-tested on large private servers. Create the `topg_votes` table with: `CREATE TABLE topg_votes (name VARCHAR(50), date DATE, rewarded TINYINT DEFAULT 0, PRIMARY KEY(name, date));` For AzerothCore specifically, Eluna is bundled by default.