├── icon.png
├── 3dfetch.conf
├── banner.png
├── jingle.wav
├── lpp-3ds.elf
├── icon_small.png
├── romfs
├── images
│ ├── logo.png
│ ├── luma.png
│ ├── rei.png
│ ├── rx.png
│ ├── rx_g.png
│ ├── rx_p.png
│ ├── rx_y.png
│ ├── cakes.png
│ ├── emote.png
│ ├── logo_g.png
│ ├── logo_p.png
│ ├── logo_w.png
│ ├── logo_y.png
│ ├── luma_g.png
│ ├── luma_p.png
│ ├── luma_w.png
│ ├── luma_y.png
│ ├── rei_g.png
│ ├── rei_p.png
│ ├── rei_y.png
│ ├── cakes_g.png
│ ├── cakes_p.png
│ ├── cakes_y.png
│ ├── corbenik.png
│ ├── emote_g.png
│ ├── emote_p.png
│ ├── emote_w.png
│ ├── emote_y.png
│ ├── isabelle.png
│ ├── corbenik_g.png
│ ├── corbenik_p.png
│ └── corbenik_y.png
└── index.lua
├── Makefile
├── README.md
└── 3dfetch.rsf
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/icon.png
--------------------------------------------------------------------------------
/3dfetch.conf:
--------------------------------------------------------------------------------
1 | showAnimation:true
2 | showSplash:false
3 | showCFW:false
4 |
--------------------------------------------------------------------------------
/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/banner.png
--------------------------------------------------------------------------------
/jingle.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/jingle.wav
--------------------------------------------------------------------------------
/lpp-3ds.elf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/lpp-3ds.elf
--------------------------------------------------------------------------------
/icon_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/icon_small.png
--------------------------------------------------------------------------------
/romfs/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/logo.png
--------------------------------------------------------------------------------
/romfs/images/luma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/luma.png
--------------------------------------------------------------------------------
/romfs/images/rei.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rei.png
--------------------------------------------------------------------------------
/romfs/images/rx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rx.png
--------------------------------------------------------------------------------
/romfs/images/rx_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rx_g.png
--------------------------------------------------------------------------------
/romfs/images/rx_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rx_p.png
--------------------------------------------------------------------------------
/romfs/images/rx_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rx_y.png
--------------------------------------------------------------------------------
/romfs/images/cakes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/cakes.png
--------------------------------------------------------------------------------
/romfs/images/emote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/emote.png
--------------------------------------------------------------------------------
/romfs/images/logo_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/logo_g.png
--------------------------------------------------------------------------------
/romfs/images/logo_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/logo_p.png
--------------------------------------------------------------------------------
/romfs/images/logo_w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/logo_w.png
--------------------------------------------------------------------------------
/romfs/images/logo_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/logo_y.png
--------------------------------------------------------------------------------
/romfs/images/luma_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/luma_g.png
--------------------------------------------------------------------------------
/romfs/images/luma_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/luma_p.png
--------------------------------------------------------------------------------
/romfs/images/luma_w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/luma_w.png
--------------------------------------------------------------------------------
/romfs/images/luma_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/luma_y.png
--------------------------------------------------------------------------------
/romfs/images/rei_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rei_g.png
--------------------------------------------------------------------------------
/romfs/images/rei_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rei_p.png
--------------------------------------------------------------------------------
/romfs/images/rei_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/rei_y.png
--------------------------------------------------------------------------------
/romfs/images/cakes_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/cakes_g.png
--------------------------------------------------------------------------------
/romfs/images/cakes_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/cakes_p.png
--------------------------------------------------------------------------------
/romfs/images/cakes_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/cakes_y.png
--------------------------------------------------------------------------------
/romfs/images/corbenik.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/corbenik.png
--------------------------------------------------------------------------------
/romfs/images/emote_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/emote_g.png
--------------------------------------------------------------------------------
/romfs/images/emote_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/emote_p.png
--------------------------------------------------------------------------------
/romfs/images/emote_w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/emote_w.png
--------------------------------------------------------------------------------
/romfs/images/emote_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/emote_y.png
--------------------------------------------------------------------------------
/romfs/images/isabelle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/isabelle.png
--------------------------------------------------------------------------------
/romfs/images/corbenik_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/corbenik_g.png
--------------------------------------------------------------------------------
/romfs/images/corbenik_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/corbenik_p.png
--------------------------------------------------------------------------------
/romfs/images/corbenik_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliceinpalth/3dfetch/HEAD/romfs/images/corbenik_y.png
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | AUTHORS="yyualice & daedreth"
2 | OBJECTS_TO_CLEAN=3ds 3dfetch.cia banner.bnr 3dfetch.smdh romfs.bin 3dfetch.3dsx
3 | CIA_DEPENDENCIES=lpp-3ds.elf romfs.bin banner.bnr 3dfetch.smdh 3dfetch.rsf
4 |
5 |
6 | 3dfetch.cia: ${CIA_DEPENDENCIES}
7 | makerom -f cia -o $@ -DAPP_ENCRYPTED=false -rsf 3dfetch.rsf -target t -exefslogo -elf lpp-3ds.elf -icon 3dfetch.smdh -banner banner.bnr -romfs romfs.bin
8 |
9 | # This one is for debugging purposes, some functionality is broken unless using a CIA
10 | .PHONY: 3dsx
11 | 3dsx: 3dfetch.3dsx
12 | 3dslink $<
13 |
14 | .PHONY: cia
15 | cia: 3dfetch.cia
16 | $(info ********** cia file built **********)
17 |
18 | 3dfetch.3dsx: 3dfetch.smdh
19 | mkdir -p 3ds/3dfetch
20 | 3dsxtool lpp-3ds.elf $@ --romfs=romfs/ --smdh=$<
21 | cp $@ 3ds/3dfetch/$@
22 | cp $< 3ds/3dfetch/$<
23 |
24 | romfs.bin: lpp-3ds.elf
25 | 3dstool -cvtf romfs $@ --romfs-dir romfs/
26 |
27 | banner.bnr: romfs.bin banner.png jingle.wav
28 | bannertool makebanner -i banner.png -a jingle.wav -o $@
29 |
30 | 3dfetch.smdh: banner.bnr icon.png
31 | bannertool makesmdh -s "3dfetch" -l "3dfetch" -p ${AUTHORS} -i icon.png -o $@
32 |
33 | .PHONY: clean
34 | clean:
35 | rm -rf ${OBJECTS_TO_CLEAN}
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 
4 |
5 | Similar to Linux's screenfetch script, but unsigned and executed on a Nintendo 3DS. RSF file based off of [this dummy RSF](https://gist.github.com/mid-kid/d9c4ce50407c71ec9ef3). Mainly developed as a method for learning 3DS homebrew toolkits, libraries, and build environments.
6 |
7 | # Features
8 | - Pretty colors!
9 | - Cycle through text colors using the d-pad, and background colors using the L and R buttons
10 | - Press the A button to take a screenshot, saved to the SD card root as ` 3dfetch_day_month_year_x.jpg `
11 | - All information dynamically grabbed from 3DS' hardware
12 | - New 3DS and old 3DS compatible
13 | - Press select for a configuration menu
14 | - Use in tandem with [imgurup-3ds](https://github.com/Pirater12/imgurup-3ds) for an easy sharing experience
15 |
16 | # Screenshots
17 | 
18 |
19 |
20 | 3dfetch running on a New 3DS with Luma CFW.
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | A screenshot generated by 3dfetch on a New 3DS with Luma CFW.
29 |
30 |
31 | # Where to get it
32 | Check the [releases page](https://github.com/yyualice/3dfetch/releases) for a CIA file / QR code. Or get it on TitleDB within FBI.
33 |
34 | # Optional configuration
35 | 3dfetch can optionally be configured by creating a file at the root of your SD card called `3dfetch.conf`. At present, the following options are available:
36 |
37 | `showAnimation:true | false` to enable/disable the little shell animation on startup.
38 |
39 | `showSplash:true | false` to enable/disable the CFW splash on the bottom
40 |
41 | `showCFW:true | false` to enable/disable CFW detection
42 |
43 | # Reporting issues
44 | Is your CFW not being recognized properly? Is the amount of free space reported incorrectly? Or maybe you came across an error.
45 |
46 | Create an issue on GitHub. Don't forget to add your CFW, what version you are on and which 3dfetch version/commit you were using.
47 |
48 | # Building from source
49 | ## Requirements
50 | - [`makerom`](https://github.com/profi200/Project_CTR/releases) to create the CIA.
51 | - [`3ds-tool`](https://github.com/dnasdw/3dstool/releases) to recompile the ROM filesystem.
52 | - [`bannertool`](https://github.com/Steveice10/bannertool) to create the banner and icon files.
53 | - A fork of lpp-3ds found [here](https://github.com/daedreth/lpp-3ds) which includes expanded functionality. The compiled binary (`lpp-3ds.elf`) is included in the repository, we strongly suggest against attempts to compile it yourself, if such necessity arises, visit the forks repository for instructions.
54 |
55 | ## Compiling
56 | ### CIA
57 | Run `make` to build an installable CIA-file.
58 |
59 | ### 3dsx
60 | If you wish to use 3dfetch inside the Homebrew Launcher and thus require a 3dsx file, run `make 3dfetch.3dsx` instead and merge the `/3ds` folder with the one found on your SD card.
61 |
62 | ### Network-sent 3dsx
63 | If you would like to have 3dfetch be sent via network to your console, open up the Homebrew Launcher, press `Y` and run `make 3dsx` instead.
64 |
--------------------------------------------------------------------------------
/3dfetch.rsf:
--------------------------------------------------------------------------------
1 | BasicInfo:
2 | Title : "3dfetch"
3 | ProductCode : "CTR-HB-3DFE"
4 | Logo : Nintendo
5 |
6 | RomFs:
7 | #RootPath : romfs
8 |
9 | TitleInfo:
10 | Category : Application
11 | UniqueId : 0x9f99e
12 |
13 | Option:
14 | UseOnSD : true # true if App is to be installed to SD
15 | FreeProductCode : true # Removes limitations on ProductCode
16 | MediaFootPadding : false # If true CCI files are created with padding
17 | EnableCrypt : false # Enables encryption for NCCH and CIA
18 | EnableCompress : true # Compresses where applicable (currently only exefs:/.code)
19 |
20 | AccessControlInfo:
21 | CoreVersion : 2
22 |
23 | # Exheader Format Version
24 | DescVersion : 2
25 |
26 | # Minimum Required Kernel Version (below is for 4.5.0)
27 | ReleaseKernelMajor : "02"
28 | ReleaseKernelMinor : "33"
29 |
30 | # FS:USER Archive Access Permissions
31 | # Uncomment as required
32 | FileSystemAccess:
33 | #- CategorySystemApplication
34 | #- CategoryHardwareCheck
35 | - CategoryFileSystemTool
36 | #- Debug
37 | #- TwlCardBackup
38 | #- TwlNandData
39 | #- Boss
40 | - DirectSdmc
41 | #- Core
42 | #- CtrNandRo
43 | #- CtrNandRw
44 | #- CtrNandRoWrite
45 | #- CategorySystemSettings
46 | #- CardBoard
47 | #- ExportImportIvs
48 | #- DirectSdmcWrite
49 | #- SwitchCleanup
50 | #- SaveDataMove
51 | #- Shop
52 | #- Shell
53 | #- CategoryHomeMenu
54 | IoAccessControl:
55 | #- FsMountNand
56 | #- FsMountNandRoWrite
57 | #- FsMountTwln
58 | #- FsMountWnand
59 | #- FsMountCardSpi
60 | #- UseSdif3
61 | #- CreateSeed
62 | #- UseCardSpi
63 |
64 | # Process Settings
65 | MemoryType : Application # Application/System/Base
66 | SystemMode : 64MB # 64MB(Default)/96MB/80MB/72MB/32MB
67 | IdealProcessor : 0
68 | AffinityMask : 1
69 | Priority : 16
70 | MaxCpu : 0x9E # Default
71 | HandleTableSize : 0x200
72 | DisableDebug : false
73 | EnableForceDebug : false
74 | CanWriteSharedPage : true
75 | CanUsePrivilegedPriority : false
76 | CanUseNonAlphabetAndNumber : true
77 | PermitMainFunctionArgument : true
78 | CanShareDeviceMemory : true
79 | RunnableOnSleep : false
80 | SpecialMemoryArrange : true
81 |
82 | # VA Mappings
83 | IORegisterMapping:
84 | - 1ff00000-1ff7ffff
85 | MemoryMapping:
86 | - 1f000000-1f5fffff:r
87 |
88 | # Accessible SVCs, :
89 | SystemCallAccess:
90 | ArbitrateAddress: 34
91 | Backdoor: 123
92 | Break: 60
93 | CancelTimer: 28
94 | ClearEvent: 25
95 | ClearTimer: 29
96 | CloseHandle: 35
97 | ConnectToPort: 45
98 | ControlMemory: 1
99 | ControlProcessMemory: 112
100 | CreateAddressArbiter: 33
101 | CreateEvent: 23
102 | CreateMemoryBlock: 30
103 | CreateMutex: 19
104 | CreateSemaphore: 21
105 | CreateThread: 8
106 | CreateTimer: 26
107 | DuplicateHandle: 39
108 | ExitProcess: 3
109 | ExitThread: 9
110 | GetCurrentProcessorNumber: 17
111 | GetHandleInfo: 41
112 | GetProcessId: 53
113 | GetProcessIdOfThread: 54
114 | GetProcessIdealProcessor: 6
115 | GetProcessInfo: 43
116 | GetResourceLimit: 56
117 | GetResourceLimitCurrentValues: 58
118 | GetResourceLimitLimitValues: 57
119 | GetSystemInfo: 42
120 | GetSystemTick: 40
121 | GetThreadContext: 59
122 | GetThreadId: 55
123 | GetThreadIdealProcessor: 15
124 | GetThreadInfo: 44
125 | GetThreadPriority: 11
126 | MapMemoryBlock: 31
127 | OutputDebugString: 61
128 | QueryMemory: 2
129 | ReleaseMutex: 20
130 | ReleaseSemaphore: 22
131 | SendSyncRequest1: 46
132 | SendSyncRequest2: 47
133 | SendSyncRequest3: 48
134 | SendSyncRequest4: 49
135 | SendSyncRequest: 50
136 | SetThreadPriority: 12
137 | SetTimer: 27
138 | SignalEvent: 24
139 | SleepThread: 10
140 | UnmapMemoryBlock: 32
141 | WaitSynchronization1: 36
142 | WaitSynchronizationN: 37
143 | InterruptNumbers:
144 |
145 | # Service List
146 | # Maximum 34 services (32 if firmware is prior to 9.6.0)
147 | ServiceAccessControl:
148 | - APT:U
149 | - ac:u
150 | - am:net
151 | - boss:U
152 | - cam:u
153 | - cecd:u
154 | - cfg:nor
155 | - cfg:u
156 | - csnd:SND
157 | - dsp::DSP
158 | - frd:u
159 | - fs:USER
160 | - gsp::Gpu
161 | - hid:USER
162 | - http:C
163 | - ir:rst
164 | - ir:u
165 | - ir:USER
166 | - mic:u
167 | - mcu::HWC
168 | - ndm:u
169 | - news:u
170 | - nwm::UDS
171 | - ptm:u
172 | - pxi:dev
173 | - soc:U
174 | - ssl:C
175 | - y2r:u
176 |
177 | SystemControlInfo:
178 | SaveDataSize: 0KB # Change if the app uses savedata
179 | RemasterVersion: 2
180 | StackSize: 0x40000
181 |
182 | # Modules that run services listed above should be included below
183 | # Maximum 48 dependencies
184 | # :
185 | Dependency:
186 | ac: 0x0004013000002402
187 | #act: 0x0004013000003802
188 | am: 0x0004013000001502
189 | boss: 0x0004013000003402
190 | camera: 0x0004013000001602
191 | cecd: 0x0004013000002602
192 | cfg: 0x0004013000001702
193 | codec: 0x0004013000001802
194 | csnd: 0x0004013000002702
195 | dlp: 0x0004013000002802
196 | dsp: 0x0004013000001a02
197 | friends: 0x0004013000003202
198 | gpio: 0x0004013000001b02
199 | gsp: 0x0004013000001c02
200 | hid: 0x0004013000001d02
201 | http: 0x0004013000002902
202 | i2c: 0x0004013000001e02
203 | ir: 0x0004013000003302
204 | mcu: 0x0004013000001f02
205 | mic: 0x0004013000002002
206 | ndm: 0x0004013000002b02
207 | news: 0x0004013000003502
208 | #nfc: 0x0004013000004002
209 | nim: 0x0004013000002c02
210 | nwm: 0x0004013000002d02
211 | pdn: 0x0004013000002102
212 | ps: 0x0004013000003102
213 | ptm: 0x0004013000002202
214 | #qtm: 0x0004013020004202
215 | ro: 0x0004013000003702
216 | socket: 0x0004013000002e02
217 | spi: 0x0004013000002302
218 | ssl: 0x0004013000002f02
219 |
--------------------------------------------------------------------------------
/romfs/index.lua:
--------------------------------------------------------------------------------
1 | -- Some colors
2 | colors =
3 | {
4 | background = Color.new(0, 0, 0),
5 | right = Color.new(255, 255, 255),
6 | left = Color.new(0, 255, 255),
7 | red = Color.new(255, 0, 0),
8 | green = Color.new(0, 255, 0),
9 | black = Color.new(0, 0, 0)
10 | }
11 |
12 | -- Configuration option
13 | local configs =
14 | {
15 | showAnimation = true,
16 | showSplash = true,
17 | showCFW = true
18 | }
19 |
20 | -- Configuration path
21 | configPath = "/3dfetch.conf"
22 |
23 | -- Indexes
24 | colorIndex =
25 | {
26 | background = 0,
27 | right = 0,
28 | left = 0
29 | }
30 |
31 | -- Global variables
32 | fetchVer = 1.10
33 | photoNum = 0
34 | oldPad = 0
35 | lastfp = 0
36 | timer = Timer.new()
37 | shouldRenderSS = false
38 | isMenuOpen = false
39 |
40 | -- Load default graphics
41 | Graphics.init()
42 |
43 | -- Images
44 | logos =
45 | {
46 | default = Graphics.loadImage("romfs:/images/isabelle.png"),
47 | blue = Graphics.loadImage("romfs:/images/isabelle.png"),
48 | green = Graphics.loadImage("romfs:/images/isabelle.png"),
49 | pink = Graphics.loadImage("romfs:/images/isabelle.png"),
50 | yellow = Graphics.loadImage("romfs:/images/isabelle.png")
51 | }
52 |
53 | -- Rectangles!
54 | local OPTION_RECT_SIZE = {x = 275, y = 50}
55 | local MENU_RECT_SIZE = {x = 60, y = 26}
56 |
57 | -- Append a line to a file
58 | function writeLine(filePath, fileString)
59 | local file = io.open(filePath, FCREATE)
60 | local content = io.read(file, 0, io.size(file))..fileString
61 | io.write(file, 0, content, string.len(content))
62 | io.close(file)
63 | end
64 |
65 | -- Config code written by Al, all of these functions
66 | function readConfig(filePath)
67 | local fileContent = ""
68 |
69 | if System.doesFileExist(filePath) then
70 | local file = io.open(filePath, 0)
71 | fileContent = io.read(file, 0, io.size(file))
72 | io.close(file)
73 | end
74 |
75 | fileContent = string.gsub(fileContent, "\r", "") --Remove windows characters
76 | if(string.sub(fileContent, -1) == "\n") then fileContent = string.sub(fileContent, 1, -2) end
77 | return fileContent
78 | end
79 |
80 | function setConfigs(configFileContent)
81 | local configStrings = {System.split(configFileContent, "\n")}
82 | for key,value in pairs(configStrings) do
83 | local configPair = {System.split(value, ":")}
84 | local configOption = ""
85 | if (string.find(configPair[1], "\x00") ~= nil) then
86 | configOption = string.sub(configPair[1], 1, string.find(configPair[1], "\x00", 1) - 1)
87 | else
88 | configOption = configPair[1]
89 | end
90 | configs[configOption] = "true" == configPair[2]
91 | end
92 |
93 | end
94 |
95 | function writeConfig(filePath)
96 | if System.doesFileExist(filePath) then System.deleteFile(filePath) end
97 |
98 | for option,value in pairs(configs) do writeLine(filePath, option..":"..tostring(value).."\n") end
99 | end
100 |
101 | -- Text output to top screen
102 | function printTopLeftSide()
103 | local xoffset = 10
104 |
105 | Screen.debugPrint(xoffset, 10, string.lower(getUsernameString()) .. "@" .. string.lower(getCPUString(1)), colors.left, TOP_SCREEN)
106 | Screen.debugPrint(xoffset, 25, "-----------", colors.left, TOP_SCREEN)
107 | if configs.showCFW then Screen.debugPrint(xoffset, 55, "Firmware:", colors.left, TOP_SCREEN) end
108 | Screen.debugPrint(xoffset, 70, "Resolution:", colors.left, TOP_SCREEN)
109 | Screen.debugPrint(xoffset, 85, "Kernel:", colors.left, TOP_SCREEN)
110 | Screen.debugPrint(xoffset, 100, "CPU:", colors.left, TOP_SCREEN)
111 | Screen.debugPrint(xoffset, 115, "Battery:", colors.left, TOP_SCREEN)
112 | Screen.debugPrint(xoffset, 130, "Free space:", colors.left, TOP_SCREEN)
113 | Screen.debugPrint(xoffset, 160, "Region:", colors.left, TOP_SCREEN)
114 | Screen.debugPrint(xoffset, 175, "Date:", colors.left, TOP_SCREEN)
115 | end
116 |
117 | function printTopRightSide()
118 | local xoffset = 160
119 |
120 | if configs.showCFW then Screen.debugPrint(xoffset, 55, getCFWString(), colors.right, TOP_SCREEN) end
121 | Screen.debugPrint(xoffset, 70, "800x240, 320x240", colors.right, TOP_SCREEN)
122 | Screen.debugPrint(xoffset, 85, getKernelVersionString(), colors.right, TOP_SCREEN)
123 | Screen.debugPrint(xoffset, 100, getCPUString(2), colors.right, TOP_SCREEN)
124 | Screen.debugPrint(xoffset, 115, getBatteryStatusString(), colors.right, TOP_SCREEN)
125 | Screen.debugPrint(xoffset, 130, getFreeSpaceString(), colors.right, TOP_SCREEN)
126 | Screen.debugPrint(xoffset, 160, getRegionString(), colors.right, TOP_SCREEN)
127 | Screen.debugPrint(xoffset, 175, getDateString(), colors.right, TOP_SCREEN)
128 | end
129 |
130 | -- Next 3 functions take care of the current date
131 | function getMonthString(month)
132 | local monthArray =
133 | {
134 | "January",
135 | "February",
136 | "March",
137 | "April",
138 | "May",
139 | "June",
140 | "July",
141 | "August",
142 | "September",
143 | "October",
144 | "November",
145 | "December"
146 | }
147 |
148 | return monthArray[month]
149 | end
150 |
151 | function getDayString(day)
152 | local dayArray =
153 | {
154 | "Monday",
155 | "Tuesday",
156 | "Wednesday",
157 | "Thursday",
158 | "Friday",
159 | "Saturday",
160 | "Sunday"
161 | }
162 |
163 | return dayArray[day]
164 | end
165 |
166 | function getDateString()
167 | local dayValue, day, month, year = System.getDate()
168 | return getDayString(dayValue) .. " " .. getMonthString(month) .. " " .. day .. ", " .. year
169 | end
170 |
171 | function getUsernameString()
172 | return System.getUsername()
173 | end
174 |
175 | function getCPUString(value)
176 | model = System.getModel()
177 |
178 | local modelArray =
179 | {
180 | "3ds",
181 | "3dsXL",
182 | "New3DS",
183 | "2DS",
184 | "New3DSXL",
185 | "New2DSXL"
186 | }
187 |
188 | local processorArray =
189 | {
190 | "ARM11 Duocore",
191 | "ARM11 Duocore",
192 | "ARM11 Quadcore",
193 | "ARM11 Duocore",
194 | "ARM11 Quadcore",
195 | "ARM11 Quadcore",
196 | }
197 |
198 | if value == 1 then
199 | return modelArray[model + 1]
200 | elseif value == 2 then
201 | return processorArray[model + 1] .. " @ " .. System.getCpuSpeed() .. "hz"
202 | else
203 | return modelArray[model + 1], processorArray[model + 1]
204 | end
205 | end
206 |
207 | function getRegionString()
208 | regionNumber = System.getRegion()
209 |
210 | local regionArray =
211 | {
212 | "North America",
213 | "Europe",
214 | "Japan"
215 | }
216 |
217 | return regionArray[regionNumber]
218 | end
219 |
220 | function getKernelVersionString()
221 | local majorK, minorK, revisionK = System.getKernel()
222 | return majorK .. "." .. minorK .. "." .. revisionK
223 | end
224 |
225 | function getBatteryStatusString()
226 | if System.isBatteryCharging() then return "Charging @ " .. System.getBatteryPercentage() .. "%" else
227 | return "Discharging @ " .. System.getBatteryPercentage() .. "%" end
228 | end
229 |
230 | function getFreeSpaceString()
231 | return (math.floor(System.getFreeSpace()/1e9)) .. "GB"
232 | end
233 |
234 | -- Improved CFW Function
235 | -- The Luma Version checking was adapted from astronautlevel2 and his StarUpdater, all credit where it's due
236 | -- Thanks Al <3
237 | function getCFWString()
238 | local majorL,minorL,revisionL = System.getLumaVersion()
239 | local fileContent = ""
240 |
241 | if majorL ~= 0 then
242 | return "Luma3DS v" .. majorL .. "." .. minorL
243 | end
244 |
245 | if System.doesFileExist("/boot.firm") then
246 | local file = io.open("/boot.firm", 0)
247 | fileContent = io.read(file,0,io.size(file))
248 | io.close(file)
249 | elseif System.doesFileExist("/arm9loaderhax.bin") then
250 | local file = io.open("/arm9loaderhax.bin", 0)
251 | fileContent = io.read(file,0,io.size(file))
252 | io.close(file)
253 | end
254 |
255 | if string.match(fileContent, "Luma3DS") then
256 | local searchString = "Luma3DS v"
257 | local verString = "v"
258 | local isDone = false
259 | local offset = string.find(fileContent, searchString)
260 |
261 | if (offset ~= nil) then
262 | offset = offset + string.len(searchString)
263 | while(isDone == false) do
264 | bitRead = fileContent:sub(offset,offset)
265 | if bitRead == " " then
266 | isDone = true
267 | else
268 | verString = verString..bitRead
269 | end
270 | offset = offset + 1
271 | end
272 | return "Luma3DS " .. verString
273 | end
274 |
275 | elseif string.match(fileContent, "skeith") then return "Skeith"
276 | elseif string.match(fileContent, "corbenik") then return "Corbenik"
277 | elseif string.match(fileContent, "Rei") then return "ReiNAND"
278 | elseif string.match(fileContent, "cakes") then return "Cakes"
279 | end
280 |
281 |
282 | if System.doesDirectoryExist("/rxTools") or System.doesFileExist("/rxTools.dat") then return "rxTools"
283 | elseif System.doesDirectoryExist("/rei") then return "ReiNAND"
284 | elseif System.doesDirectoryExist("/aurei") then return "AuReiNAND"
285 | elseif System.doesDirectoryExist("/luma") then return "Luma3DS"
286 | elseif System.doesDirectoryExist("/cakes") then return "Cakes"
287 | end
288 | end
289 |
290 | function updateColors()
291 | if colorIndex.left == 0 then
292 | colors.left = Color.new(0,255,255) -- Pastel blue
293 | logos.default = logos.blue
294 | elseif colorIndex.left == 1 then
295 | colors.left = Color.new(255,244,53) -- Pastel yellow
296 | logos.default = logos.yellow
297 | elseif colorIndex.left == 2 then
298 | colors.left = Color.new(96,255,117) -- Pastel green
299 | logos.default = logos.green
300 | elseif colorIndex.left == 3 then
301 | colors.left = Color.new(255,170,242) -- Pastel pink
302 | logos.default = logos.pink
303 | elseif colorIndex.left > 3 then
304 | colors.left = Color.new(0,255,255) -- Pastel blue
305 | colorIndex.left = 0
306 | logos.default = logos.blue
307 | elseif colorIndex.left < 0 then
308 | colors.left = Color.new(255,204,247) -- Pastel pink
309 | colorIndex.left = 3
310 | logos.default = logos.pink
311 | end
312 |
313 | if colorIndex.right == 0 then
314 | colors.right = Color.new(255,255,255) -- White
315 | elseif colorIndex.right == 1 then
316 | colors.right = Color.new(255,244,53) -- Pastel yellow
317 | elseif colorIndex.right == 2 then
318 | colors.right = Color.new(96,255,117) -- Pastel green
319 | elseif colorIndex.right == 3 then
320 | colors.right = Color.new(61,61,61) -- Black
321 | elseif colorIndex.right > 3 then
322 | colors.right = Color.new(255,255,255) -- White
323 | colorIndex.right = 0
324 | elseif colorIndex.right < 0 then
325 | colors.right = Color.new(61,61,61) -- Black
326 | colorIndex.right = 3
327 | end
328 |
329 | if colorIndex.background == 0 then
330 | colors.background = Color.new(0,0,0) -- Black
331 | elseif colorIndex.background == 1 then
332 | colors.background = Color.new(0,98,137) -- Dark blue
333 | elseif colorIndex.background == 2 then
334 | colors.background = Color.new(255,255,255) -- White
335 | elseif colorIndex.background == 3 then
336 | colors.background = Color.new(0,175,96) -- Dark green
337 | elseif colorIndex.background > 3 then
338 | colors.background = Color.new(0,0,0) -- Black
339 | colorIndex.background = 0
340 | elseif colorIndex.background < 0 then
341 | colors.background = Color.new(0,136,21) -- Dark green
342 | colorIndex.background = 3
343 | end
344 | end
345 |
346 | function initCFWLogo()
347 | local cfw = getCFWString()
348 | if string.match(cfw, "Luma") then cfw = "Luma3DS" end
349 |
350 | local fileName =
351 | {
352 | Luma3DS = "luma",
353 | AuReiNAND = "luma",
354 | ReiNAND = "rei",
355 | rxTools = "rx",
356 | Cakes = "cakes",
357 | Skeith = "corbenik",
358 | Corbenik = "corbenik"
359 | }
360 |
361 | logos.default = Graphics.loadImage("romfs:/images/" .. fileName[cfw].. ".png")
362 | logos.blue = Graphics.loadImage("romfs:/images/" .. fileName[cfw].. ".png")
363 | logos.green = Graphics.loadImage("romfs:/images/" .. fileName[cfw].. "_g.png")
364 | logos.pink = Graphics.loadImage("romfs:/images/" .. fileName[cfw].. "_p.png")
365 | logos.yellow = Graphics.loadImage("romfs:/images/" .. fileName[cfw].. "_y.png")
366 | end
367 |
368 | function animatePrint(string, time)
369 | Screen.refresh()
370 | Screen.clear(TOP_SCREEN)
371 | Screen.debugPrint(10,10,string, colors.right, TOP_SCREEN)
372 | Screen.flip()
373 | System.sleep(time)
374 | end
375 |
376 | function animateInvocation()
377 | local ps = string.lower(getUsernameString()) .. "@" .. string.lower(getCPUString(1)) .. " ~ $ "
378 | local commandString = "3dfetch_"
379 |
380 | Screen.refresh()
381 | Graphics.initBlend(BOTTOM_SCREEN)
382 | Graphics.fillRect(0, 320, 0, 240, colors.background)
383 | Graphics.termBlend()
384 | Screen.refresh()
385 | Screen.clear(TOP_SCREEN)
386 | Screen.clear(BOTTOM_SCREEN)
387 |
388 | for i=1,string.len(commandString) do
389 | animatePrint(ps..string.sub(commandString,1,i), 2)
390 | end
391 |
392 | animatePrint(ps .. "3dfetch", 2)
393 | animatePrint(ps .. "3dfetch_", 2)
394 | animatePrint(ps .. "3dfetch", 2)
395 | animatePrint(ps .. "3dfetch_", 2)
396 |
397 | System.sleep(4)
398 | end
399 |
400 | function drawCFWLogo()
401 | Graphics.initBlend(BOTTOM_SCREEN)
402 | Graphics.fillRect(0,320,0,240,colors.background)
403 | Graphics.drawImage(0,0,logos.default)
404 | Graphics.termBlend()
405 | end
406 |
407 | -- This function was made actually good by Al. Thanks Al <3
408 | function showMenu()
409 | Graphics.initBlend(BOTTOM_SCREEN)
410 | Graphics.fillRect(0, 320, 0, 240, colors.background)
411 | Graphics.termBlend()
412 | local cur_x = 20
413 | local cur_y = 20
414 | local optionRects = {}
415 | Screen.refresh()
416 |
417 | for option,value in pairs(configs) do
418 | optionRects[option] = {val = value, x = cur_x, y = cur_y, end_x = cur_x + OPTION_RECT_SIZE["x"], end_y = cur_y + OPTION_RECT_SIZE["y"]}
419 | cur_x = cur_x + OPTION_RECT_SIZE["x"] + 20 -- 20 is for padding
420 | if (cur_x + OPTION_RECT_SIZE["x"] + 20 > 320) then
421 | cur_x = 20
422 | cur_y = cur_y + OPTION_RECT_SIZE["y"] + 20
423 | end
424 |
425 | local currentRect = optionRects[option]
426 | local color = ""
427 | if value == true then color = colors.green else color = colors.red end
428 | Screen.fillRect(currentRect["x"], currentRect["end_x"], currentRect["y"], currentRect["end_y"], color, BOTTOM_SCREEN)
429 | Screen.debugPrint(currentRect["x"], (currentRect["y"] + currentRect["end_y"]) / 2, option, colors.black, BOTTOM_SCREEN)
430 | end
431 |
432 | Screen.debugPrint(8, 217, "3dfetch Version: " .. tostring(fetchVer), colors.left, BOTTOM_SCREEN)
433 |
434 | Screen.flip()
435 | System.sleep(5)
436 | local pad = Controls.read()
437 | local touchPos_x, touchPos_y = Controls.readTouch()
438 |
439 | while not (Controls.check(pad, KEY_SELECT)) do
440 | pad = Controls.read()
441 | touchPos_x, touchPos_y = Controls.readTouch()
442 | if touchPos_x ~= 0 or touchPos_y ~= 0 then
443 | Graphics.initBlend(BOTTOM_SCREEN)
444 | Graphics.fillRect(0, 320, 0, 240, colors.background)
445 | Graphics.termBlend()
446 | Screen.refresh()
447 | for option,rect in pairs(configs) do
448 | local currentRect = optionRects[option]
449 | if currentRect["x"] < touchPos_x and currentRect["end_x"] > touchPos_x and currentRect["y"] < touchPos_y and currentRect["end_y"] > touchPos_y then
450 | configs[option] = not configs[option]
451 | end
452 | local color = ""
453 | if configs[option] == true then color = colors.green else color = colors.red end
454 | Screen.fillRect(currentRect["x"], currentRect["end_x"], currentRect["y"], currentRect["end_y"], color, BOTTOM_SCREEN)
455 | Screen.debugPrint(currentRect["x"], (currentRect["y"] + currentRect["end_y"]) / 2, option, colors.black, BOTTOM_SCREEN)
456 | end
457 | Screen.debugPrint(8, 217, "3dfetch Version: " .. tostring(fetchVer), colors.left, BOTTOM_SCREEN)
458 | Screen.flip()
459 | System.sleep(5)
460 | end
461 | end
462 | Graphics.initBlend(BOTTOM_SCREEN)
463 | Graphics.fillRect(0, 320, 0, 240, colors.background)
464 | Graphics.termBlend()
465 | Screen.refresh()
466 | Screen.flip()
467 | writeConfig(configPath)
468 | end
469 |
470 | function takeScreenshot()
471 | local day_value, day, month, year = System.getDate()
472 | local hours, minutes, seconds = System.getTime()
473 | local filepath = "/" .. "3dfetch_" .. day .. month .. year .. "_" .. hours .. minutes .. seconds
474 | lastfp = filepath
475 |
476 | System.takeScreenshot(filepath .. ".jpg", false)
477 | shouldRenderSS = true
478 | end
479 |
480 | -- Last function calls before main loop engages
481 | initCFWLogo()
482 | configContent = readConfig(configPath)
483 | if (configContent ~= "") then setConfigs(configContent) end -- if configFile is empty we just use defaults
484 | if (configs["showAnimation"]) then animateInvocation() end
485 |
486 | -- Main loop
487 | while true do
488 | seconds = math.ceil(Timer.getTime(timer)/1000)
489 |
490 | Screen.refresh()
491 |
492 | if configs.showSplash then
493 | drawCFWLogo()
494 | else
495 | Graphics.initBlend(BOTTOM_SCREEN)
496 | Graphics.fillRect(0, 320, 0, 240, colors.background)
497 | Graphics.termBlend()
498 | end
499 |
500 | Graphics.initBlend(TOP_SCREEN)
501 | Graphics.fillRect(0, 800, 0, 240, colors.background)
502 | Graphics.termBlend()
503 |
504 | pad = Controls.read()
505 |
506 | printTopLeftSide()
507 | printTopRightSide()
508 |
509 | if Controls.check(pad, KEY_A) and not (Controls.check(oldpad,KEY_A)) then
510 | takeScreenshot()
511 | end
512 |
513 | -- Menu open
514 | if Controls.check(pad, KEY_SELECT) and not (Controls.check(oldpad, KEY_SELECT)) then
515 | showMenu()
516 | end
517 |
518 | -- Cycling lcolors
519 | if Controls.check(pad, KEY_DRIGHT) and not (Controls.check(oldpad,KEY_DRIGHT)) then
520 | colorIndex.left = colorIndex.left + 1
521 | updateColors()
522 | end
523 | if Controls.check(pad, KEY_DLEFT) and not (Controls.check(oldpad,KEY_DLEFT)) then
524 | colorIndex.left = colorIndex.left - 1
525 | updateColors()
526 | end
527 |
528 | -- Cycling rcolors
529 | if Controls.check(pad, KEY_DUP) and not (Controls.check(oldpad,KEY_DUP)) then
530 | colorIndex.right = colorIndex.right + 1
531 | updateColors()
532 | end
533 | if Controls.check(pad, KEY_DDOWN) and not (Controls.check(oldpad,KEY_DDOWN)) then
534 | colorIndex.right = colorIndex.right - 1
535 | updateColors()
536 | end
537 |
538 | -- Cycling bgcolors
539 | if Controls.check(pad, KEY_R) and not (Controls.check(oldpad,KEY_R)) then
540 | colorIndex.background = colorIndex.background + 1
541 | updateColors()
542 | end
543 | if Controls.check(pad, KEY_L) and not (Controls.check(oldpad,KEY_L)) then
544 | colorIndex.background = colorIndex.background - 1
545 | updateColors()
546 | end
547 |
548 | if seconds > 5 then
549 | shouldRenderSS = false
550 | timer = Timer.new()
551 | end
552 |
553 | if shouldRenderSS == true then
554 | Screen.debugPrint(10, 10, "Screenshot saved:", colors.right, BOTTOM_SCREEN)
555 | Screen.debugPrint(10, 25, lastfp, colors.right, BOTTOM_SCREEN)
556 | end
557 |
558 | -- Flipping screen
559 | Screen.flip()
560 | Screen.waitVblankStart()
561 |
562 | oldpad = pad
563 |
564 | -- Sets up HomeMenu syscall
565 | if Controls.check(Controls.read(),KEY_HOME) or Controls.check(Controls.read(),KEY_POWER) then
566 | System.showHomeMenu()
567 | end
568 |
569 | if Controls.check(pad, KEY_START) then System.exit() end
570 |
571 | -- Exit if HomeMenu calls APP_EXITING
572 | if System.checkStatus() == APP_EXITING then
573 | System.exit()
574 | end
575 | end
576 |
--------------------------------------------------------------------------------