RCT Help Documentation
Home
  • Getting Started
  • Script Metadata
  • Custom UI
  • Core API
  • Chart Class
  • Data Classes
  • Examples
  • Best Practices
Plugin Store
  • 简体中文
  • English
Home
  • Getting Started
  • Script Metadata
  • Custom UI
  • Core API
  • Chart Class
  • Data Classes
  • Examples
  • Best Practices
Plugin Store
  • 简体中文
  • English
  • API Reference

    • Home
    • Getting Started
    • Script Metadata
    • Custom UI Dialog
    • Core API
    • Chart Class
    • Data Classes
    • Example Scripts
    • Best Practices

Best Practices

This page provides best practices and guidelines for RCT Python script development.

Development Guidelines

1. Always Check Return Values

get_current_chart() may return None, always check:

chart = get_current_chart()
if not chart:
    print("Error: Unable to get chart")
    return

# Continue processing...

2. Parameter Validation

Check length and type before using sys.argv:

import sys

if len(sys.argv) < 3:
    print("Error: Missing parameters")
    return

try:
    value = float(sys.argv[1])
except ValueError:
    print("Error: Parameter must be a number")
    return

3. Use Exception Handling

Catch potential errors and provide friendly error messages:

try:
    chart = load_chart_from_file("path/to/chart.txt")
    # Process chart...
except FileNotFoundError:
    print("Error: File not found")
except Exception as e:
    print(f"Error: {e}")

4. Output Detailed Information

Use print() to output processing results, messages will appear in RCT status bar:

print(f"Processing complete: Kept {len(chart.notes)} notes")
print(f"Time range: {min_time}ms - {max_time}ms")

5. Sort Before Saving

Call chart.sort() after modifying notes to ensure correct order:

chart.add_note(Note.TAP, 1000, 45)
chart.add_note(Note.TAP, 500, 90)

chart.sort()  # Important! Ensure chronological order
save_current_chart(chart)

6. Backup Important Charts

Backup chart files before testing new scripts:

from rct_api import get_current_chart, save_chart_to_file

chart = get_current_chart()
if chart:
    # Create backup
    save_chart_to_file(chart, "backup/chart_backup.txt")
    
    # Then make modifications...

Code Standards

File Structure

Recommended script file structure:

# Description: Script description
# Args: Parameter description (optional)
# UI: UI configuration (optional)

import sys
import json
from rct_api import get_current_chart, save_current_chart, Note

def main():
    """Main function"""
    # Parameter checking
    if len(sys.argv) < 2:
        print("Error: Missing parameters")
        return
    
    # Get chart
    chart = get_current_chart()
    if not chart:
        print("Error: Unable to get chart")
        return
    
    # Processing logic
    try:
        # ... your code ...
        
        # Save
        save_current_chart(chart)
        print("Processing complete")
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

Naming Conventions

  • File names: Use lowercase letters and underscores, e.g., shift_time.py
  • Function names: Use lowercase letters and underscores, e.g., process_notes()
  • Variable names: Use descriptive names, e.g., start_time instead of st

Commenting Conventions

# Single-line comment: Explain code intent

"""
Multi-line comment or docstring:
Detailed function description, parameters, and return values
"""

def filter_by_time(chart, start, end):
    """
    Filter notes by time range
    
    Args:
        chart: Chart object
        start: Start time (milliseconds)
        end: End time (milliseconds)
    """
    chart.filter_notes_by_time(start, end)

Performance Optimization

1. Avoid Repeated Operations

Not recommended:

for i in range(len(chart.notes)):
    note = chart.notes[i]
    # Process...

Recommended:

for note in chart.notes:
    # Process...

2. Batch Processing

Not recommended:

for i in range(100):
    chart.add_note(Note.TAP, i * 1000, 45)
    chart.sort()  # Sorting each time is inefficient
    save_current_chart(chart)

Recommended:

for i in range(100):
    chart.add_note(Note.TAP, i * 1000, 45)

chart.sort()  # Sort only once
save_current_chart(chart)

3. Use List Comprehensions

Not recommended:

filtered_notes = []
for note in chart.notes:
    if note.type == Note.TAP:
        filtered_notes.append(note)
chart.notes = filtered_notes

Recommended:

chart.notes = [note for note in chart.notes if note.type == Note.TAP]

Debugging Tips

1. Output Debug Information

print(f"[DEBUG] Number of notes: {len(chart.notes)}")
print(f"[DEBUG] First note: type={chart.notes[0].type}, time={chart.notes[0].time}")

2. Step-by-Step Testing

Break complex operations into multiple steps, test gradually:

# Step 1: Read and display information only
chart = get_current_chart()
print(f"Number of notes: {len(chart.notes)}")

# Step 2: Add small amount of test data
# chart.add_note(Note.TAP, 1000, 45)
# save_current_chart(chart)

# Step 3: Full functionality
# ... complete code ...

3. Use Conditional Import

Add local test code during development:

DEBUG = True  # Set to True during development

if DEBUG:
    print("[DEBUG] Entering debug mode")
    # Use test data...
else:
    chart = get_current_chart()

Common Errors

1. Forgetting to Check for None

❌ Wrong:

chart = get_current_chart()
print(len(chart.notes))  # Error if chart is None

✅ Correct:

chart = get_current_chart()
if chart:
    print(len(chart.notes))
else:
    print("Error: Unable to get chart")

2. Parameter Type Error

❌ Wrong:

offset = sys.argv[1]  # This is a string
chart.shift_time(offset)  # Needs a number

✅ Correct:

offset = float(sys.argv[1])  # Convert to float
chart.shift_time(offset)

3. Forgetting to Sort

❌ Wrong:

chart.add_note(Note.TAP, 3000, 90)
chart.add_note(Note.TAP, 1000, 45)
save_current_chart(chart)  # Order is mixed up

✅ Correct:

chart.add_note(Note.TAP, 3000, 90)
chart.add_note(Note.TAP, 1000, 45)
chart.sort()  # Sort
save_current_chart(chart)

4. Iteration Issues When Modifying List

❌ Wrong:

for note in chart.notes:
    if note.type == Note.BOMB:
        chart.notes.remove(note)  # Modifying list during iteration

✅ Correct:

chart.notes = [note for note in chart.notes if note.type != Note.BOMB]

Important Notes

Time Units

  • Always use milliseconds (ms) as the time unit
  • Angle range is 0-360 degrees
# 1 second = 1000 milliseconds
one_second = 1000

# Half circle = 180 degrees
half_circle = 180

Custom UI Configuration

  • JSON configuration must be on the same line (single-line comment format)
  • Or use triple-quoted string format (recommended)
  • All default_value are in string format
# Single-line format
# UI: {"fields":[{"name":"value","field_type":"number","label":"Value:","default_value":"10","options":[]}]}

# Or triple-quoted format (recommended)
"""UI:{
  "fields": [...]
}"""

File Naming

  • Don't use Chinese characters or special characters
  • Use lowercase letters and underscores
  • Use descriptive names

Save Operations

  • Must call save_current_chart() after modifying chart
  • Save operations cannot be undone
  • Backup important charts first

Security Recommendations

1. Data Validation

Always validate user input:

if start_time < 0:
    print("Error: Start time cannot be negative")
    return

if end_time <= start_time:
    print("Error: End time must be greater than start time")
    return

2. Boundary Checks

if len(chart.notes) == 0:
    print("Warning: Chart has no notes")
    return

if len(chart.bpm) == 0:
    print("Warning: Chart has no BPM information")
    return

3. Limit Operation Scope

# Limit number of generated notes
MAX_NOTES = 10000

if count > MAX_NOTES:
    print(f"Error: Number of notes cannot exceed {MAX_NOTES}")
    return

Advanced Tips

1. Use Configuration Files

import json

# Read configuration
with open("config.json", "r") as f:
    config = json.load(f)

default_bpm = config.get("default_bpm", 120)

2. Command-Line Argument Parsing

Use argparse for more user-friendly parameter handling:

import argparse

parser = argparse.ArgumentParser(description="Note time shifting tool")
parser.add_argument("offset", type=float, help="Time offset (milliseconds)")
parser.add_argument("--verbose", action="store_true", help="Display detailed information")

args = parser.parse_args()
offset = args.offset

3. Modular Design

Encapsulate common functionality into functions:

def validate_time_range(start, end):
    """Validate time range"""
    if start < 0 or end < 0:
        return False, "Time cannot be negative"
    if end <= start:
        return False, "End time must be greater than start time"
    return True, ""

# Usage
valid, error = validate_time_range(start, end)
if not valid:
    print(f"Error: {error}")
    return

Related Resources

  • Getting Started - Introductory guide
  • Core API - API function reference
  • Example Scripts - Practical example code
Prev
Example Scripts