-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathembedded_data.go
More file actions
144 lines (124 loc) · 4.58 KB
/
Copy pathembedded_data.go
File metadata and controls
144 lines (124 loc) · 4.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"embed"
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"strings"
)
//go:embed data/shelllab.db
var embeddedDB []byte
//go:embed data/icons/*
var embeddedIcons embed.FS
//go:embed data/npc_images/*
var embeddedNpcImages embed.FS
// InitializeData ensures data directory exists and extracts embedded database on first run
// Icons are NOT embedded - they remain external and can be updated independently
// Returns the absolute path to the data directory and whether we're in dev mode
func InitializeData() (string, bool, error) {
var baseDir string
// Detect if running in dev mode (wails dev)
// In dev mode, the executable is in build/bin/ directory or a temp directory
// We want to use the current working directory (project root) instead
exePath, err := os.Executable()
if err != nil {
return "", false, fmt.Errorf("failed to get executable path: %w", err)
}
// Check if we're running from dev mode locations:
// - build/bin (wails dev on Windows/Linux)
// - Temp/tmp (some dev environments)
isDevMode := strings.Contains(exePath, "Temp") ||
strings.Contains(exePath, "tmp") ||
strings.Contains(exePath, "build"+string(os.PathSeparator)+"bin") ||
strings.Contains(exePath, "build/bin")
if isDevMode {
// Dev mode: use current working directory (project root)
cwd, err := os.Getwd()
if err != nil {
return "", false, fmt.Errorf("failed to get working directory: %w", err)
}
baseDir = cwd
log.Println("🔧 Development mode detected, using project root:", baseDir)
} else {
// Production mode: use executable directory
baseDir = filepath.Dir(exePath)
log.Println("📦 Production mode, using executable directory:", baseDir)
}
dataDir := filepath.Join(baseDir, "data")
iconsDir := filepath.Join(dataDir, "icons")
dbPath := filepath.Join(dataDir, "shelllab.db")
// Create directories
if err := os.MkdirAll(iconsDir, 0755); err != nil {
return "", false, fmt.Errorf("failed to create data directory: %w", err)
}
// In production, extract database if not exists
// In dev mode, we don't extract - we use the existing data/shelllab.db directly
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
log.Println("Extracting embedded database...")
if err := os.WriteFile(dbPath, embeddedDB, 0644); err != nil {
return "", false, fmt.Errorf("failed to write database: %w", err)
}
log.Println("✓ Database extracted to", dbPath)
} else {
log.Println("✓ Using existing database:", dbPath)
}
// Extract icons if directory is empty or mostly empty (< 50 icons)
entries, _ := os.ReadDir(iconsDir)
if len(entries) < 50 {
log.Println("Extracting embedded icons (this may take a moment)...")
extractAssets(embeddedIcons, "data/icons", iconsDir)
log.Println("📝 Tip: Downloaded icons will be saved to data/icons/ and take precedence over embedded ones")
}
// Extract NPC images if directory is empty
npcImagesDir := filepath.Join(dataDir, "npc_images")
if err := os.MkdirAll(npcImagesDir, 0755); err != nil {
log.Printf("Warning: Failed to create npc_images directory: %v", err)
} else {
npcEntries, _ := os.ReadDir(npcImagesDir)
if len(npcEntries) < 5 { // Only extract if very few images exist
log.Println("Extracting embedded NPC images...")
extractAssets(embeddedNpcImages, "data/npc_images", npcImagesDir)
}
}
return dataDir, isDevMode, nil
}
// extractAssets extracts files from an embedded FS to a destination directory
func extractAssets(embedFs embed.FS, srcDir string, destDir string) error {
count := 0
err := fs.WalkDir(embedFs, srcDir, func(path string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return err
}
// Read from embedded FS
content, err := embedFs.ReadFile(path)
if err != nil {
return err
}
// Write to the correct dataDir location
relPath, _ := filepath.Rel(srcDir, path)
localPath := filepath.Join(destDir, relPath)
// Create parent directory if needed (e.g. for nested resources)
if err := os.MkdirAll(filepath.Dir(localPath), 0755); err != nil {
return err
}
// Only write if file doesn't exist (preserve user updates)
if _, err := os.Stat(localPath); os.IsNotExist(err) {
if err := os.WriteFile(localPath, content, 0644); err != nil {
return err
}
count++
if count%100 == 0 {
log.Printf(" Extracted %d files...", count)
}
}
return nil
})
if err != nil {
log.Printf("Error extracting assets: %v", err)
return err
}
log.Printf("✓ Extracted %d files to %s", count, destDir)
return nil
}