Skip to content

Latest commit

 

History

History
390 lines (300 loc) · 8.9 KB

File metadata and controls

390 lines (300 loc) · 8.9 KB

MVU Variable Framework API

Complete reference for MagVarUpdate (MVU) framework - a Tavern Helper script that enhances message floor variable management.

Overview

MVU is a separate Tavern Helper script that provides:

  • Set variables in world info entries
  • Initialize variables from world info or chat history
  • Auto-update variables from AI output
  • Visualization support (display_data, delta_data)

Initialization

Always wait for MVU before using:

await waitGlobalInitialized('Mvu');

// Now safe to use Mvu functions
const data = Mvu.getMvuData({ type: 'message', message_id: -1 });

Data Storage

MVU stores data in message floor variables at stat_data path:

// These are equivalent:
Mvu.getMvuData({ type: 'message', message_id: 5 })
_.get(getVariables({ type: 'message', message_id: 5 }), 'stat_data')

Additional fields MVU sets:

  • stat_data - Actual variable values
  • display_data - Formatted for display (with units, colors, etc.)
  • delta_data - Variable changes since last message

Core API

Mvu.getMvuData()

Get MVU data from message floor.

function getMvuData(option: {
  type: 'message',
  message_id: number | 'latest'
}): Record<string, any>

Examples:

// Get latest message MVU data
const latest = Mvu.getMvuData({ type: 'message', message_id: 'latest' });

// Get specific message (negative = from end)
const prev = Mvu.getMvuData({ type: 'message', message_id: -2 });

// Access specific variables
console.log(latest.hp);    // 100
console.log(latest.score); // 42

Mvu.replaceMvuData()

Write MVU data to message floor.

function replaceMvuData(
  data: Record<string, any>,
  option: {
    type: 'message',
    message_id: number | 'latest'
  }
): void

Examples:

// Update latest message
Mvu.replaceMvuData({ hp: 80, mp: 50 }, {
  type: 'message',
  message_id: 'latest'
});

// Update specific message
Mvu.replaceMvuData(newData, {
  type: 'message',
  message_id: 5
});

Mvu.parseMessage()

Parse AI output for MVU commands and return updated data.

Important: Does NOT automatically write back to message floor.

function parseMessage(
  oldData: Record<string, any>,
  message: string
): Promise<{
  stat_data: Record<string, any>;
  display_data: Record<string, any>;
  delta_data: Record<string, any>;
}>

Usage scenario: When generating AI output manually (not through normal chat flow).

Example:

// Get old state
const oldData = Mvu.getMvuData({ type: 'message', message_id: -2 });

// Generate AI response manually
const aiOutput = await generate({
  prompt: 'What happens next?'
});

// Parse MVU commands in AI output
const newData = await Mvu.parseMessage(oldData, aiOutput);

// Manually write back
Mvu.replaceMvuData(newData.stat_data, {
  type: 'message',
  message_id: -1
});

// Also update display and delta if needed
const messageVars = getVariables({ type: 'message', message_id: -1 });
messageVars.display_data = newData.display_data;
messageVars.delta_data = newData.delta_data;
replaceVariables(messageVars, { type: 'message', message_id: -1 });

Why not auto-write?: Gives you fine-grained control over when and how data is saved.

Events

MVU provides events for monitoring variable changes.

Mvu.events

Enum of available MVU events.

declare const Mvu: {
  events: {
    BEFORE_UPDATE: string;  // Before variables update
    AFTER_UPDATE: string;   // After variables update
    PARSE_ERROR: string;    // Parse error occurred
  }
}

Listening to MVU Events

import { eventOn } from '@types/iframe/event';

// After variables updated
eventOn(Mvu.events.AFTER_UPDATE, (data: {
  message_id: number;
  stat_data: Record<string, any>;
  display_data: Record<string, any>;
  delta_data: Record<string, any>;
}) => {
  console.log('Variables updated for message', data.message_id);
  console.log('New values:', data.stat_data);
  console.log('Changes:', data.delta_data);
});

// Before update (for validation/modification)
eventOn(Mvu.events.BEFORE_UPDATE, (data) => {
  // Can modify data here before it's saved
  if (data.stat_data.hp < 0) {
    data.stat_data.hp = 0;
  }
});

// Parse errors
eventOn(Mvu.events.PARSE_ERROR, (error: {
  message_id: number;
  error: string;
}) => {
  console.error('MVU parse error:', error);
  toastr.error(`Variable parse failed: ${error.error}`);
});

Common Patterns

Display Variable Changes

eventOn(Mvu.events.AFTER_UPDATE, (data) => {
  // Show what changed in UI
  Object.entries(data.delta_data).forEach(([key, delta]) => {
    if (delta > 0) {
      toastr.success(`${key} +${delta}`);
    } else if (delta < 0) {
      toastr.warning(`${key} ${delta}`);
    }
  });
});

Sync MVU Data with Vue State

import { ref, watch } from 'vue';
import { klona } from 'klona';

const gameState = ref({
  hp: 100,
  mp: 50,
  gold: 0
});

// Load from latest message
$(() => {
  const mvuData = Mvu.getMvuData({ type: 'message', message_id: 'latest' });
  gameState.value = { ...gameState.value, ...mvuData };
});

// Listen for AI updates
eventOn(Mvu.events.AFTER_UPDATE, (data) => {
  // Update Vue state when AI changes variables
  gameState.value = { ...gameState.value, ...data.stat_data };
});

// Optional: Write back to MVU when user changes state
watch(gameState, (newState) => {
  Mvu.replaceMvuData(klona(newState), {
    type: 'message',
    message_id: 'latest'
  });
}, { deep: true });

Validate Variables Before Save

eventOn(Mvu.events.BEFORE_UPDATE, (data) => {
  // Clamp HP between 0-100
  if (data.stat_data.hp !== undefined) {
    data.stat_data.hp = Math.max(0, Math.min(100, data.stat_data.hp));
  }

  // Prevent negative gold
  if (data.stat_data.gold !== undefined && data.stat_data.gold < 0) {
    data.stat_data.gold = 0;
  }

  // Auto-calculate derived stats
  data.stat_data.max_hp = (data.stat_data.level || 1) * 10;
});

Custom Variable Visualization

eventOn(Mvu.events.AFTER_UPDATE, (data) => {
  // Update custom UI
  const $statusBar = $('#game-status-bar');

  // HP bar
  const hpPercent = (data.stat_data.hp / data.stat_data.max_hp) * 100;
  $statusBar.find('.hp-bar').css('width', `${hpPercent}%`);

  // Show delta with animation
  Object.entries(data.delta_data).forEach(([key, delta]) => {
    const $deltaText = $(`<span class="delta-text">${delta > 0 ? '+' : ''}${delta}</span>`);
    $statusBar.find(`.${key}-value`).after($deltaText);

    gsap.to($deltaText[0], {
      y: -50,
      opacity: 0,
      duration: 1,
      onComplete: () => $deltaText.remove()
    });
  });
});

MVU Command Syntax

MVU commands are embedded in AI output. Here are common patterns:

Basic Variable Update

[hp: 80]
[mp: 50]
[gold: +10]

With Display Format

[hp: 80 | ❤️ 80/100]
[exp: +50 | ⭐ 150/200]

Conditional Updates

[if combat=true | hp: -20]
[if level>=5 | skill_unlocked: true]

Note: Frontend/script developers don't need to parse these - MVU handles it automatically. Just read the resulting stat_data.

Integration Example

Complete example of MVU-powered status display:

import { ref } from 'vue';
import { klona } from 'klona';

// Wait for MVU
await waitGlobalInitialized('Mvu');

// State
const gameState = ref({
  hp: 100,
  max_hp: 100,
  mp: 50,
  max_mp: 50,
  gold: 0,
  level: 1
});

// Load initial state
const initialData = Mvu.getMvuData({ type: 'message', message_id: 'latest' });
Object.assign(gameState.value, initialData);

// Listen for updates
eventOn(Mvu.events.AFTER_UPDATE, (data) => {
  // Update state
  Object.assign(gameState.value, data.stat_data);

  // Show changes
  Object.entries(data.delta_data).forEach(([key, delta]) => {
    if (Math.abs(delta) > 0) {
      toastr.info(`${key}: ${delta > 0 ? '+' : ''}${delta}`);
    }
  });
});

// Validate on save
eventOn(Mvu.events.BEFORE_UPDATE, (data) => {
  // Clamp HP
  data.stat_data.hp = Math.max(0, Math.min(data.stat_data.max_hp, data.stat_data.hp));

  // Clamp MP
  data.stat_data.mp = Math.max(0, Math.min(data.stat_data.max_mp, data.stat_data.mp));
});

Best Practices

✅ DO

  • Always await waitGlobalInitialized('Mvu') before using
  • Use AFTER_UPDATE event for UI synchronization
  • Use BEFORE_UPDATE for validation and derived calculations
  • Handle negative message_id for relative indexing
  • Check if MVU data exists before accessing properties

❌ DON'T

  • Don't assume MVU is always available (user may not have it installed)
  • Don't parse MVU commands yourself (let MVU do it)
  • Don't forget to call replaceMvuData() after parseMessage()
  • Don't directly modify display_data or delta_data (MVU manages these)

Type Definitions

Full TypeScript definitions available at:

  • @types/iframe/exported.mvu.d.ts

Related Documentation

  • api_reference.md - Tavern Helper API
  • best_practices.md - General development guidelines