You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

364 lines
11 KiB

#!/usr/bin/env python3
"""
Example: Loading StarCraft Assets into a Game Engine
=====================================================
This is a conceptual example showing how to load and use extracted
StarCraft assets in a hypothetical game engine.
This demonstrates:
- Loading audio files
- Loading and displaying graphics
- Parsing data files
- Organizing assets for runtime use
Note: This is educational/demonstration code for engine developers.
"""
from pathlib import Path
from typing import Dict, List, Optional
import struct
class AssetManager:
"""
Example asset manager for a game engine.
This shows how to organize and load StarCraft assets for use
in an alternative game engine.
"""
def __init__(self, assets_dir: str = "assets"):
self.assets_dir = Path(assets_dir)
self.audio_cache = {}
self.graphics_cache = {}
self.data_cache = {}
print(f"AssetManager initialized with: {self.assets_dir}")
def load_audio(self, audio_id: int) -> Optional[bytes]:
"""
Load an audio file by its ID.
Args:
audio_id: Numeric ID (e.g., 123 for File00000123.wav)
Returns:
Audio data as bytes, or None if not found
"""
# Check cache first
if audio_id in self.audio_cache:
return self.audio_cache[audio_id]
# Find file
filename = f"File{audio_id:08d}.wav"
audio_path = self.assets_dir / "audio" / filename
if not audio_path.exists():
print(f" Audio {audio_id} not found: {filename}")
return None
# Load file
with open(audio_path, 'rb') as f:
data = f.read()
# Cache it
self.audio_cache[audio_id] = data
print(f"✓ Loaded audio {audio_id}: {len(data)} bytes")
return data
def load_pcx_image(self, filename: str) -> Optional[Dict]:
"""
Load a PCX image file.
Args:
filename: Name of PCX file
Returns:
Dictionary with image data, or None if failed
"""
# Check cache
if filename in self.graphics_cache:
return self.graphics_cache[filename]
pcx_path = self.assets_dir / "graphics" / filename
if not pcx_path.exists():
print(f" Image not found: {filename}")
return None
# Try to load with PIL if available
try:
from PIL import Image
img = Image.open(pcx_path)
image_data = {
'width': img.width,
'height': img.height,
'mode': img.mode,
'data': img.tobytes(),
'palette': img.getpalette() if img.mode == 'P' else None,
'path': str(pcx_path)
}
self.graphics_cache[filename] = image_data
print(f"✓ Loaded image {filename}: {img.width}x{img.height} {img.mode}")
return image_data
except ImportError:
print(" PIL/Pillow not available - returning raw data")
with open(pcx_path, 'rb') as f:
raw_data = f.read()
return {'raw': raw_data, 'path': str(pcx_path)}
except Exception as e:
print(f"✗ Failed to load {filename}: {e}")
return None
def load_palette(self, palette_name: str) -> Optional[List[tuple]]:
"""
Load a color palette file.
Args:
palette_name: Name of palette file (.pal or .wpe)
Returns:
List of (R, G, B) tuples, or None if failed
"""
pal_path = self.assets_dir / "data" / palette_name
if not pal_path.exists():
print(f" Palette not found: {palette_name}")
return None
try:
with open(pal_path, 'rb') as f:
data = f.read(768) # 256 colors * 3 bytes
palette = []
for i in range(0, 768, 3):
r, g, b = data[i], data[i+1], data[i+2]
palette.append((r, g, b))
print(f"✓ Loaded palette {palette_name}: 256 colors")
return palette
except Exception as e:
print(f"✗ Failed to load palette {palette_name}: {e}")
return None
def search_assets(self, pattern: str) -> List[Path]:
"""
Search for assets matching a pattern.
Args:
pattern: Search pattern (e.g., "*.wav", "unit*")
Returns:
List of matching file paths
"""
matches = list(self.assets_dir.rglob(pattern))
return [m for m in matches if m.is_file()]
def get_asset_info(self, category: str) -> Dict:
"""
Get information about a category of assets.
Args:
category: Category name (e.g., "audio", "graphics")
Returns:
Dictionary with count and size information
"""
category_dir = self.assets_dir / category
if not category_dir.exists():
return {'exists': False}
files = [f for f in category_dir.rglob("*") if f.is_file()]
total_size = sum(f.stat().st_size for f in files)
return {
'exists': True,
'count': len(files),
'total_size': total_size,
'files': [f.name for f in files[:10]] # Sample
}
class GameEngine:
"""
Conceptual game engine showing asset integration.
This demonstrates how a real game engine might use the
extracted StarCraft assets.
"""
def __init__(self):
self.assets = AssetManager()
self.loaded_sounds = {}
self.loaded_textures = {}
print("\n" + "="*80)
print("Game Engine Initialized")
print("="*80)
def preload_common_sounds(self):
"""Preload commonly used sound effects"""
print("\nPreloading common sounds...")
# Example: Load first 10 sound files
for sound_id in range(29, 39): # Based on actual file numbers
audio_data = self.assets.load_audio(sound_id)
if audio_data:
self.loaded_sounds[sound_id] = audio_data
print(f"✓ Preloaded {len(self.loaded_sounds)} sounds")
def preload_ui_graphics(self):
"""Preload UI graphics"""
print("\nPreloading UI graphics...")
# Search for PCX files
pcx_files = self.assets.search_assets("*.pcx")
# Load first few as examples
for pcx_file in pcx_files[:3]:
img_data = self.assets.load_pcx_image(pcx_file.name)
if img_data:
self.loaded_textures[pcx_file.stem] = img_data
print(f"✓ Preloaded {len(self.loaded_textures)} textures")
def print_asset_summary(self):
"""Print summary of available assets"""
print("\n" + "="*80)
print("Asset Summary")
print("="*80)
categories = ['audio', 'graphics', 'video', 'data', 'maps']
for category in categories:
info = self.assets.get_asset_info(category)
if info['exists']:
size_mb = info['total_size'] / 1024 / 1024
print(f"\n📁 {category.upper()}/")
print(f" Files: {info['count']}")
print(f" Size: {size_mb:.1f} MB")
if info['files']:
print(f" Sample files:")
for filename in info['files'][:3]:
print(f" - {filename}")
def play_sound(self, sound_id: int):
"""
Play a sound effect (conceptual).
In a real engine, this would:
1. Get audio data from cache or load it
2. Decode the WAV format
3. Send to audio mixer
4. Play through audio device
"""
print(f"\n🔊 Playing sound {sound_id}...")
if sound_id in self.loaded_sounds:
audio_data = self.loaded_sounds[sound_id]
print(f" Using cached audio: {len(audio_data)} bytes")
else:
audio_data = self.assets.load_audio(sound_id)
if not audio_data:
print(f" ✗ Sound not found!")
return
# In real engine: decode and play audio
print(f" ✓ Audio ready for playback")
def render_texture(self, texture_name: str):
"""
Render a texture (conceptual).
In a real engine, this would:
1. Get texture from cache or load it
2. Upload to GPU
3. Render to screen with proper coordinates
"""
print(f"\n🖼 Rendering texture: {texture_name}")
if texture_name in self.loaded_textures:
tex_data = self.loaded_textures[texture_name]
if 'width' in tex_data:
print(f" Using cached texture: {tex_data['width']}x{tex_data['height']}")
else:
print(f" Using raw texture data")
else:
print(f" Texture not in cache - would load on demand")
# In real engine: upload to GPU and render
print(f" ✓ Texture rendered")
def demo():
"""Run a demonstration of asset loading"""
print("\n" + "="*80)
print("StarCraft Asset Loading Demo")
print("="*80)
print("\nThis demonstrates how a game engine would load extracted assets")
print()
# Check if assets exist
if not Path("assets").exists():
print("❌ Assets directory not found!")
print("\nPlease extract assets first:")
print(" python extract_starcraft_assets.py")
return
# Create engine instance
engine = GameEngine()
# Show available assets
engine.print_asset_summary()
# Preload common assets
print("\n" + "="*80)
print("Preloading Assets")
print("="*80)
engine.preload_common_sounds()
engine.preload_ui_graphics()
# Simulate gameplay
print("\n" + "="*80)
print("Simulating Game Actions")
print("="*80)
# Play some sounds
engine.play_sound(29)
engine.play_sound(35)
# Render some textures
if engine.loaded_textures:
first_texture = list(engine.loaded_textures.keys())[0]
engine.render_texture(first_texture)
# Summary
print("\n" + "="*80)
print("Demo Complete!")
print("="*80)
print(f"\nLoaded in memory:")
print(f" Sounds: {len(engine.loaded_sounds)}")
print(f" Textures: {len(engine.loaded_textures)}")
print("\nThis demonstrates the basics of asset loading.")
print("A real engine would include:")
print(" - Audio decoding and playback")
print(" - Texture uploading to GPU")
print(" - Sprite rendering with animations")
print(" - Data table parsing (units, weapons, etc.)")
print(" - Map loading and terrain rendering")
print()
if __name__ == "__main__":
demo()