├── 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 | ![](http://i.imgur.com/49vYhos.png) 2 | 3 | ![Github Releases](https://img.shields.io/github/downloads/aliceinpalth/3dfetch/latest/total.svg?style=flat-square) 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 | ![3dfetch running a New 3DS](http://i.imgur.com/OWcdNhB.jpg) 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 | --------------------------------------------------------------------------------