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_timeinstead ofst
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_valueare 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