mirror of
https://github.com/azahar-emu/ArticSetupTool
synced 2025-11-06 15:10:01 +01:00
Initial commit
This commit is contained in:
commit
f36e54a5b5
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
images/logo.pdn
|
||||||
|
.vscode/
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "plugin/ArticProtocol"]
|
||||||
|
path = plugin/ArticProtocol
|
||||||
|
url = https://github.com/PabloMK7/ArticProtocol.git
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 PabloMK7
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
18
Makefile
Normal file
18
Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
VERSION_MAJOR := 1
|
||||||
|
VERSION_MINOR := 2
|
||||||
|
VERSION_REVISION := 0
|
||||||
|
|
||||||
|
all:
|
||||||
|
mkdir -p plugin/build
|
||||||
|
sed -e 's/VERSION_MAJOR/$(VERSION_MAJOR)/' -e 's/VERSION_MINOR/$(VERSION_MINOR)/' -e 's/VERSION_REVISION/$(VERSION_REVISION)/' plugin/AzaharArticSetup.plgInfo > plugin/build/AzaharArticSetup.plgInfo
|
||||||
|
$(MAKE) -C plugin VERSION_MAJOR=$(VERSION_MAJOR) VERSION_MINOR=$(VERSION_MINOR) VERSION_REVISION=$(VERSION_REVISION)
|
||||||
|
bin2c -d app/includes/plugin.h -o app/sources/plugin.c plugin/AzaharArticSetup.3gx
|
||||||
|
$(MAKE) -C app VERSION_MAJOR=$(VERSION_MAJOR) VERSION_MINOR=$(VERSION_MINOR) VERSION_REVISION=$(VERSION_REVISION)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C plugin clean
|
||||||
|
rm -f app/sources/plugin.c
|
||||||
|
rm -f app/includes/plugin.h
|
||||||
|
$(MAKE) -C app clean
|
||||||
|
|
||||||
|
re: clean all
|
||||||
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Azahar Artic Setup Tool
|
||||||
|
|
||||||
|
## Description
|
||||||
|
**Azahar Artic Setup Tool** is a 3DS homebrew application that helps doing the initial setup of the [Azahar Emulator](https://github.com/azahar-emu/azahar) using your console. It broadcasts the System Settings application as well as the NIM sysmodule to be able to perform a system update. Furthermore, it copies your console unique data to be able to use online functionality.
|
||||||
|
|
||||||
|
## Usage instructions
|
||||||
|
1) Download the `.cia` or `.3dsx` file from the [releases page](https://github.com/azahar-emu/ArticSetupTool/releases) and install it.
|
||||||
|
2) Run the Azahar Artic Setup Tool application. Press A to confirm you want to start it.
|
||||||
|
3) On the Azahar Emulator, go to `File -> Initial Setup` and enter the IP address displayed on your console.
|
||||||
|
|
||||||
|
NOTE: A recent version of Luma3DS (v13.3.1 or newer) is requires to use Azahar Artic Setup Tool. You can get it [here](https://github.com/LumaTeam/Luma3DS/releases/latest).
|
||||||
|
|
||||||
|
## License
|
||||||
|
See [LICENSE](LICENSE)
|
||||||
|
|
||||||
8
app/.gitignore
vendored
Normal file
8
app/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/build
|
||||||
|
*.3gx
|
||||||
|
.vscode/
|
||||||
|
output/
|
||||||
|
*.map
|
||||||
|
|
||||||
|
includes/plugin.h
|
||||||
|
sources/plugin.c
|
||||||
82
app/Makefile
Normal file
82
app/Makefile
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# TARGET #
|
||||||
|
|
||||||
|
|
||||||
|
TARGET := 3DS
|
||||||
|
LIBRARY := 0
|
||||||
|
|
||||||
|
ifeq ($(TARGET),$(filter $(TARGET),3DS WIIU))
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro")
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# COMMON CONFIGURATION #
|
||||||
|
|
||||||
|
NAME := Azahar Artic Setup
|
||||||
|
|
||||||
|
BUILD_DIR := build
|
||||||
|
OUTPUT_DIR := output
|
||||||
|
SOURCE_DIRS := sources
|
||||||
|
INCLUDE_DIRS := $(SOURCE_DIRS) includes
|
||||||
|
|
||||||
|
EXTRA_OUTPUT_FILES :=
|
||||||
|
|
||||||
|
LIBRARY_DIRS := $(PORTLIBS) $(CTRULIB) $(DEVKITPRO)/libcwav $(DEVKITPRO)/libncsnd
|
||||||
|
LIBRARIES := ctru
|
||||||
|
|
||||||
|
VERSION_MAJOR := 1
|
||||||
|
VERSION_MINOR := 0
|
||||||
|
VERSION_MICRO := 0
|
||||||
|
|
||||||
|
BUILD_FLAGS := -march=armv6k -mtune=mpcore -mfloat-abi=hard
|
||||||
|
BUILD_FLAGS_CC := -g -Wall -Wno-strict-aliasing -O3 -mword-relocations \
|
||||||
|
-fomit-frame-pointer -ffast-math $(ARCH) $(INCLUDE) -D__3DS__ $(BUILD_FLAGS) \
|
||||||
|
-DVERSION_MAJOR=${VERSION_MAJOR} \
|
||||||
|
-DVERSION_MINOR=${VERSION_MINOR} \
|
||||||
|
-DVERSION_REVISION=${VERSION_MICRO}
|
||||||
|
|
||||||
|
BUILD_FLAGS_CXX := $(BUILD_FLAGS_CC) $(COMMON_FLAGS) -fno-rtti -fno-exceptions -std=gnu++20
|
||||||
|
RUN_FLAGS :=
|
||||||
|
|
||||||
|
# 3DS/Wii U CONFIGURATION #
|
||||||
|
|
||||||
|
ifeq ($(TARGET),$(filter $(TARGET),3DS WIIU))
|
||||||
|
TITLE := Azahar Artic Setup Tool
|
||||||
|
DESCRIPTION := Setup tool for Azahar Emulator
|
||||||
|
AUTHOR := PabloMK7
|
||||||
|
endif
|
||||||
|
|
||||||
|
# 3DS CONFIGURATION #
|
||||||
|
|
||||||
|
ifeq ($(TARGET),3DS)
|
||||||
|
LIBRARY_DIRS += $(DEVKITPRO)/libctru $(DEVKITPRO)/portlibs/3ds/
|
||||||
|
LIBRARIES += ctru
|
||||||
|
|
||||||
|
PRODUCT_CODE := CTR-P-AAST
|
||||||
|
UNIQUE_ID := 0xAE5E7
|
||||||
|
|
||||||
|
CATEGORY := Application
|
||||||
|
USE_ON_SD := true
|
||||||
|
|
||||||
|
MEMORY_TYPE := Application
|
||||||
|
SYSTEM_MODE := 64MB
|
||||||
|
SYSTEM_MODE_EXT := Legacy
|
||||||
|
CPU_SPEED := 268MHz
|
||||||
|
ENABLE_L2_CACHE := true
|
||||||
|
|
||||||
|
ICON_FLAGS := --flags visible,recordusage
|
||||||
|
|
||||||
|
BANNER_AUDIO := resources/audio.cwav
|
||||||
|
|
||||||
|
BANNER_IMAGE := resources/banner.png
|
||||||
|
|
||||||
|
ICON := resources/icon.png
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
# INTERNAL #
|
||||||
|
|
||||||
|
include buildtools/make_base
|
||||||
|
|
||||||
|
re : clean all
|
||||||
|
.PHONY: re
|
||||||
10
app/buildtools/.buildconfig
Normal file
10
app/buildtools/.buildconfig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[default]
|
||||||
|
name=Default
|
||||||
|
runtime=host
|
||||||
|
config-opts=
|
||||||
|
run-opts=
|
||||||
|
prefix=/home/steven/.cache/gnome-builder/install/buildtools/host
|
||||||
|
app-id=
|
||||||
|
postbuild=
|
||||||
|
prebuild=
|
||||||
|
default=true
|
||||||
BIN
app/buildtools/3ds/logo.bcma.lz
Normal file
BIN
app/buildtools/3ds/logo.bcma.lz
Normal file
Binary file not shown.
92
app/buildtools/3ds/servefiles.py
Normal file
92
app/buildtools/3ds/servefiles.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
try:
|
||||||
|
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
||||||
|
from SocketServer import TCPServer
|
||||||
|
from urlparse import urljoin
|
||||||
|
from urllib import pathname2url, quote
|
||||||
|
except ImportError:
|
||||||
|
from http.server import SimpleHTTPRequestHandler
|
||||||
|
from socketserver import TCPServer
|
||||||
|
from urllib.parse import urljoin, quote
|
||||||
|
from urllib.request import pathname2url
|
||||||
|
|
||||||
|
if len(sys.argv) < 3 or len(sys.argv) > 5:
|
||||||
|
print('Usage: ' + sys.argv[0] + ' <target ip> <file / directory> [host ip] [host port]')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
accepted_extension = ('.cia', '.tik', '.cetk')
|
||||||
|
target_ip = sys.argv[1]
|
||||||
|
target_path = sys.argv[2]
|
||||||
|
hostPort = 8080 # Default value
|
||||||
|
|
||||||
|
if not os.path.exists(target_path):
|
||||||
|
print(target_path + ': No such file or directory.')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
hostIp = sys.argv[3]
|
||||||
|
if len(sys.argv) == 5:
|
||||||
|
hostPort = int(sys.argv[4])
|
||||||
|
else:
|
||||||
|
print('Detecting host IP...')
|
||||||
|
hostIp = [(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]
|
||||||
|
|
||||||
|
print('Preparing data...')
|
||||||
|
baseUrl = hostIp + ':' + str(hostPort) + '/'
|
||||||
|
|
||||||
|
if os.path.isfile(target_path):
|
||||||
|
if target_path.endswith(accepted_extension):
|
||||||
|
file_list_payload = baseUrl + quote(os.path.basename(target_path))
|
||||||
|
directory = os.path.dirname(target_path) # get file directory
|
||||||
|
else:
|
||||||
|
print('Unsupported file extension. Supported extensions are: ' + accepted_extension)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
else:
|
||||||
|
directory = target_path # it's a directory
|
||||||
|
file_list_payload = '' # init the payload before adding lines
|
||||||
|
for file in [file for file in next(os.walk(target_path))[2] if file.endswith(accepted_extension)]:
|
||||||
|
file_list_payload += baseUrl + quote(file) + '\n'
|
||||||
|
|
||||||
|
if len(file_list_payload) == 0:
|
||||||
|
print('No files to serve.')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
file_list_payloadBytes = file_list_payload.encode('ascii')
|
||||||
|
|
||||||
|
if directory and directory != '.': # doesn't need to move if it's already the current working directory
|
||||||
|
os.chdir(directory) # set working directory to the right folder to be able to serve files
|
||||||
|
|
||||||
|
print('\nURLs:')
|
||||||
|
print(file_list_payload + '\n')
|
||||||
|
|
||||||
|
print('Opening HTTP server on port ' + str(hostPort))
|
||||||
|
server = TCPServer(('', hostPort), SimpleHTTPRequestHandler)
|
||||||
|
thread = threading.Thread(target=server.serve_forever)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
try:
|
||||||
|
print('Sending URL(s) to ' + target_ip + ' on port 5000...')
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.connect((target_ip, 5000))
|
||||||
|
sock.sendall(struct.pack('!L', len(file_list_payloadBytes)) + file_list_payloadBytes)
|
||||||
|
while len(sock.recv(1)) < 1:
|
||||||
|
time.sleep(0.05)
|
||||||
|
sock.close()
|
||||||
|
except Exception as e:
|
||||||
|
print('An error occurred: ' + str(e))
|
||||||
|
server.shutdown()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print('Shutting down HTTP server...')
|
||||||
|
server.shutdown()
|
||||||
286
app/buildtools/3ds/template.rsf
Normal file
286
app/buildtools/3ds/template.rsf
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
BasicInfo:
|
||||||
|
Title : $(APP_TITLE)
|
||||||
|
ProductCode : $(APP_PRODUCT_CODE)
|
||||||
|
Logo : Homebrew
|
||||||
|
|
||||||
|
RomFs:
|
||||||
|
RootPath: $(APP_ROMFS)
|
||||||
|
|
||||||
|
TitleInfo:
|
||||||
|
Category : $(APP_CATEGORY)
|
||||||
|
UniqueId : $(APP_UNIQUE_ID)
|
||||||
|
|
||||||
|
Option:
|
||||||
|
UseOnSD : $(APP_USE_ON_SD) # true if App is to be installed to SD
|
||||||
|
FreeProductCode : true # Removes limitations on ProductCode
|
||||||
|
MediaFootPadding : false # If true CCI files are created with padding
|
||||||
|
EnableCrypt : $(APP_ENCRYPTED) # Enables encryption for NCCH and CIA
|
||||||
|
EnableCompress : true # Compresses where applicable (currently only exefs:/.code)
|
||||||
|
|
||||||
|
AccessControlInfo:
|
||||||
|
CoreVersion : 2
|
||||||
|
|
||||||
|
# Exheader Format Version
|
||||||
|
DescVersion : 2
|
||||||
|
|
||||||
|
# Minimum Required Kernel Version (below is for 4.5.0)
|
||||||
|
ReleaseKernelMajor : "02"
|
||||||
|
ReleaseKernelMinor : "33"
|
||||||
|
|
||||||
|
# ExtData
|
||||||
|
UseExtSaveData : false # enables ExtData
|
||||||
|
#ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId
|
||||||
|
|
||||||
|
# FS:USER Archive Access Permissions
|
||||||
|
# Uncomment as required
|
||||||
|
FileSystemAccess:
|
||||||
|
- CategorySystemApplication
|
||||||
|
- CategoryHardwareCheck
|
||||||
|
- CategoryFileSystemTool
|
||||||
|
- Debug
|
||||||
|
- TwlCardBackup
|
||||||
|
- TwlNandData
|
||||||
|
- Boss
|
||||||
|
- DirectSdmc
|
||||||
|
- Core
|
||||||
|
- CtrNandRo
|
||||||
|
- CtrNandRw
|
||||||
|
- CtrNandRoWrite
|
||||||
|
- CategorySystemSettings
|
||||||
|
- CardBoard
|
||||||
|
- ExportImportIvs
|
||||||
|
- DirectSdmcWrite
|
||||||
|
- SwitchCleanup
|
||||||
|
- SaveDataMove
|
||||||
|
- Shop
|
||||||
|
- Shell
|
||||||
|
- CategoryHomeMenu
|
||||||
|
- SeedDB
|
||||||
|
IoAccessControl:
|
||||||
|
- FsMountNand
|
||||||
|
- FsMountNandRoWrite
|
||||||
|
- FsMountTwln
|
||||||
|
- FsMountWnand
|
||||||
|
- FsMountCardSpi
|
||||||
|
- UseSdif3
|
||||||
|
- CreateSeed
|
||||||
|
- UseCardSpi
|
||||||
|
|
||||||
|
# Process Settings
|
||||||
|
MemoryType : $(APP_MEMORY_TYPE) # Application/System/Base
|
||||||
|
SystemMode : $(APP_SYSTEM_MODE) # 64MB(Default)/96MB/80MB/72MB/32MB
|
||||||
|
IdealProcessor : 0
|
||||||
|
AffinityMask : 1
|
||||||
|
Priority : 16
|
||||||
|
MaxCpu : 0x9E # Default
|
||||||
|
HandleTableSize : 0x200
|
||||||
|
DisableDebug : false
|
||||||
|
EnableForceDebug : false
|
||||||
|
CanWriteSharedPage : true
|
||||||
|
CanUsePrivilegedPriority : false
|
||||||
|
CanUseNonAlphabetAndNumber : true
|
||||||
|
PermitMainFunctionArgument : true
|
||||||
|
CanShareDeviceMemory : true
|
||||||
|
RunnableOnSleep : false
|
||||||
|
SpecialMemoryArrange : true
|
||||||
|
|
||||||
|
# New3DS Exclusive Process Settings
|
||||||
|
SystemModeExt : $(APP_SYSTEM_MODE_EXT) # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode
|
||||||
|
CpuSpeed : $(APP_CPU_SPEED) # 268MHz(Default)/804MHz
|
||||||
|
EnableL2Cache : $(APP_ENABLE_L2_CACHE) # false(default)/true
|
||||||
|
CanAccessCore2 : true
|
||||||
|
|
||||||
|
# Virtual Address Mappings
|
||||||
|
IORegisterMapping:
|
||||||
|
- 1ff00000-1ff7ffff # DSP memory
|
||||||
|
MemoryMapping:
|
||||||
|
- 1f000000-1f5fffff:r # VRAM
|
||||||
|
|
||||||
|
# Accessible SVCs, <Name>:<ID>
|
||||||
|
SystemCallAccess:
|
||||||
|
ControlMemory: 1
|
||||||
|
QueryMemory: 2
|
||||||
|
ExitProcess: 3
|
||||||
|
GetProcessAffinityMask: 4
|
||||||
|
SetProcessAffinityMask: 5
|
||||||
|
GetProcessIdealProcessor: 6
|
||||||
|
SetProcessIdealProcessor: 7
|
||||||
|
CreateThread: 8
|
||||||
|
ExitThread: 9
|
||||||
|
SleepThread: 10
|
||||||
|
GetThreadPriority: 11
|
||||||
|
SetThreadPriority: 12
|
||||||
|
GetThreadAffinityMask: 13
|
||||||
|
SetThreadAffinityMask: 14
|
||||||
|
GetThreadIdealProcessor: 15
|
||||||
|
SetThreadIdealProcessor: 16
|
||||||
|
GetCurrentProcessorNumber: 17
|
||||||
|
Run: 18
|
||||||
|
CreateMutex: 19
|
||||||
|
ReleaseMutex: 20
|
||||||
|
CreateSemaphore: 21
|
||||||
|
ReleaseSemaphore: 22
|
||||||
|
CreateEvent: 23
|
||||||
|
SignalEvent: 24
|
||||||
|
ClearEvent: 25
|
||||||
|
CreateTimer: 26
|
||||||
|
SetTimer: 27
|
||||||
|
CancelTimer: 28
|
||||||
|
ClearTimer: 29
|
||||||
|
CreateMemoryBlock: 30
|
||||||
|
MapMemoryBlock: 31
|
||||||
|
UnmapMemoryBlock: 32
|
||||||
|
CreateAddressArbiter: 33
|
||||||
|
ArbitrateAddress: 34
|
||||||
|
CloseHandle: 35
|
||||||
|
WaitSynchronization1: 36
|
||||||
|
WaitSynchronizationN: 37
|
||||||
|
SignalAndWait: 38
|
||||||
|
DuplicateHandle: 39
|
||||||
|
GetSystemTick: 40
|
||||||
|
GetHandleInfo: 41
|
||||||
|
GetSystemInfo: 42
|
||||||
|
GetProcessInfo: 43
|
||||||
|
GetThreadInfo: 44
|
||||||
|
ConnectToPort: 45
|
||||||
|
SendSyncRequest1: 46
|
||||||
|
SendSyncRequest2: 47
|
||||||
|
SendSyncRequest3: 48
|
||||||
|
SendSyncRequest4: 49
|
||||||
|
SendSyncRequest: 50
|
||||||
|
OpenProcess: 51
|
||||||
|
OpenThread: 52
|
||||||
|
GetProcessId: 53
|
||||||
|
GetProcessIdOfThread: 54
|
||||||
|
GetThreadId: 55
|
||||||
|
GetResourceLimit: 56
|
||||||
|
GetResourceLimitLimitValues: 57
|
||||||
|
GetResourceLimitCurrentValues: 58
|
||||||
|
GetThreadContext: 59
|
||||||
|
Break: 60
|
||||||
|
OutputDebugString: 61
|
||||||
|
ControlPerformanceCounter: 62
|
||||||
|
CreatePort: 71
|
||||||
|
CreateSessionToPort: 72
|
||||||
|
CreateSession: 73
|
||||||
|
AcceptSession: 74
|
||||||
|
ReplyAndReceive1: 75
|
||||||
|
ReplyAndReceive2: 76
|
||||||
|
ReplyAndReceive3: 77
|
||||||
|
ReplyAndReceive4: 78
|
||||||
|
ReplyAndReceive: 79
|
||||||
|
BindInterrupt: 80
|
||||||
|
UnbindInterrupt: 81
|
||||||
|
InvalidateProcessDataCache: 82
|
||||||
|
StoreProcessDataCache: 83
|
||||||
|
FlushProcessDataCache: 84
|
||||||
|
StartInterProcessDma: 85
|
||||||
|
StopDma: 86
|
||||||
|
GetDmaState: 87
|
||||||
|
RestartDma: 88
|
||||||
|
DebugActiveProcess: 96
|
||||||
|
BreakDebugProcess: 97
|
||||||
|
TerminateDebugProcess: 98
|
||||||
|
GetProcessDebugEvent: 99
|
||||||
|
ContinueDebugEvent: 100
|
||||||
|
GetProcessList: 101
|
||||||
|
GetThreadList: 102
|
||||||
|
GetDebugThreadContext: 103
|
||||||
|
SetDebugThreadContext: 104
|
||||||
|
QueryDebugProcessMemory: 105
|
||||||
|
ReadProcessMemory: 106
|
||||||
|
WriteProcessMemory: 107
|
||||||
|
SetHardwareBreakPoint: 108
|
||||||
|
GetDebugThreadParam: 109
|
||||||
|
ControlProcessMemory: 112
|
||||||
|
MapProcessMemory: 113
|
||||||
|
UnmapProcessMemory: 114
|
||||||
|
CreateCodeSet: 115
|
||||||
|
CreateProcess: 117
|
||||||
|
TerminateProcess: 118
|
||||||
|
SetProcessResourceLimits: 119
|
||||||
|
CreateResourceLimit: 120
|
||||||
|
SetResourceLimitValues: 121
|
||||||
|
AddCodeSegment: 122
|
||||||
|
Backdoor: 123
|
||||||
|
KernelSetState: 124
|
||||||
|
QueryProcessMemory: 125
|
||||||
|
|
||||||
|
# Service List
|
||||||
|
# Maximum 34 services (32 if firmware is prior to 9.6.0)
|
||||||
|
ServiceAccessControl:
|
||||||
|
- APT:U
|
||||||
|
- ac:u
|
||||||
|
- am:net
|
||||||
|
- boss:U
|
||||||
|
- cam:u
|
||||||
|
- cecd:u
|
||||||
|
- cfg:nor
|
||||||
|
- cfg:u
|
||||||
|
- csnd:SND
|
||||||
|
- dsp::DSP
|
||||||
|
- frd:u
|
||||||
|
- fs:USER
|
||||||
|
- gsp::Gpu
|
||||||
|
- gsp::Lcd
|
||||||
|
- hid:USER
|
||||||
|
- http:C
|
||||||
|
- ir:rst
|
||||||
|
- ir:u
|
||||||
|
- ir:USER
|
||||||
|
- mic:u
|
||||||
|
- mcu::HWC
|
||||||
|
- ndm:u
|
||||||
|
- news:s
|
||||||
|
- nwm::EXT
|
||||||
|
- nwm::UDS
|
||||||
|
- ptm:sysm
|
||||||
|
- ptm:u
|
||||||
|
- pxi:dev
|
||||||
|
- soc:U
|
||||||
|
- ssl:C
|
||||||
|
- y2r:u
|
||||||
|
|
||||||
|
|
||||||
|
SystemControlInfo:
|
||||||
|
SaveDataSize: 0KB # Change if the app uses savedata
|
||||||
|
RemasterVersion: $(APP_VERSION_MAJOR)
|
||||||
|
StackSize: 0x40000
|
||||||
|
|
||||||
|
# Modules that run services listed above should be included below
|
||||||
|
# Maximum 48 dependencies
|
||||||
|
# <module name>:<module titleid>
|
||||||
|
Dependency:
|
||||||
|
ac: 0x0004013000002402
|
||||||
|
#act: 0x0004013000003802
|
||||||
|
am: 0x0004013000001502
|
||||||
|
boss: 0x0004013000003402
|
||||||
|
camera: 0x0004013000001602
|
||||||
|
cecd: 0x0004013000002602
|
||||||
|
cfg: 0x0004013000001702
|
||||||
|
codec: 0x0004013000001802
|
||||||
|
csnd: 0x0004013000002702
|
||||||
|
dlp: 0x0004013000002802
|
||||||
|
dsp: 0x0004013000001a02
|
||||||
|
friends: 0x0004013000003202
|
||||||
|
gpio: 0x0004013000001b02
|
||||||
|
gsp: 0x0004013000001c02
|
||||||
|
hid: 0x0004013000001d02
|
||||||
|
http: 0x0004013000002902
|
||||||
|
i2c: 0x0004013000001e02
|
||||||
|
ir: 0x0004013000003302
|
||||||
|
mcu: 0x0004013000001f02
|
||||||
|
mic: 0x0004013000002002
|
||||||
|
ndm: 0x0004013000002b02
|
||||||
|
news: 0x0004013000003502
|
||||||
|
#nfc: 0x0004013000004002
|
||||||
|
nim: 0x0004013000002c02
|
||||||
|
nwm: 0x0004013000002d02
|
||||||
|
pdn: 0x0004013000002102
|
||||||
|
ps: 0x0004013000003102
|
||||||
|
ptm: 0x0004013000002202
|
||||||
|
#qtm: 0x0004013020004202
|
||||||
|
ro: 0x0004013000003702
|
||||||
|
socket: 0x0004013000002e02
|
||||||
|
spi: 0x0004013000002302
|
||||||
|
ssl: 0x0004013000002f02
|
||||||
13
app/buildtools/README.md
Normal file
13
app/buildtools/README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# buildtools
|
||||||
|
|
||||||
|
Common build tools for C/C++ projects. Supports PC and 3DS targets.
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
* [makerom](https://github.com/profi200/Project_CTR/tree/master/makerom/) - Building 3DS/CIA files.
|
||||||
|
* [bannertool](https://github.com/Steveice10/bannertool/) - Building 3DS/CIA files.
|
||||||
|
* [citra](https://github.com/citra-emu/citra/) - Testing 3DS/CIA builds on a PC.
|
||||||
|
* zip - Zipping up output files.
|
||||||
|
* xxd - Embedding binary files in executables.
|
||||||
|
* python - Installing CIA builds to a 3DS over the network.
|
||||||
|
|
||||||
|
Credit for 3DS homebrew logo goes to [PabloMK7](http://gbatemp.net/members/pablomk7.345712/).
|
||||||
757
app/buildtools/make_base
Normal file
757
app/buildtools/make_base
Normal file
@ -0,0 +1,757 @@
|
|||||||
|
# Make Variables
|
||||||
|
#
|
||||||
|
# TARGET: Optional; Platform to build for.
|
||||||
|
# - Supported values: NATIVE, NATIVE32, NATIVE64, WIN32, WIN64, MAC32, MAC64, LINUX32, LINUX64, 3DS, WIIU, SWITCH
|
||||||
|
# - Default value: NATIVE
|
||||||
|
# LIBRARY: Optional; Whether to output a library.
|
||||||
|
# - Supported values: 0, 1
|
||||||
|
# - Default value: 0
|
||||||
|
#
|
||||||
|
# All:
|
||||||
|
# - NAME: Project name.
|
||||||
|
# - INCLUDE_DIRS: Directories containing include headers.
|
||||||
|
# - SOURCE_DIRS: Directories containing source files to compile.
|
||||||
|
# - BUILD_DIR: Directory to store build files in.
|
||||||
|
# - OUTPUT_DIR: Directory to output the final results to.
|
||||||
|
# - LIBRARY_DIRS: Optional; Directories containing libraries to compile against.
|
||||||
|
# - LIBRARIES: Optional; Libraries to compile against.
|
||||||
|
# - EXTRA_OUTPUT_FILES: Optional; Extra files to copy to the output directory.
|
||||||
|
# - BUILD_FLAGS: Optional; Shared build flags.
|
||||||
|
# - BUILD_FLAGS_CC: Optional; C build flags.
|
||||||
|
# - BUILD_FLAGS_CXX: Optional; C++ build flags.
|
||||||
|
# - RUN_FLAGS: Optional; Flags to pass when running output executables.
|
||||||
|
# - VERSION_MAJOR: Optional; Major version number.
|
||||||
|
# - Default value: 0
|
||||||
|
# - VERSION_MINOR: Optional; Minor version number.
|
||||||
|
# - Default value: 0
|
||||||
|
# - VERSION_MICRO: Optional; Micro version number.
|
||||||
|
# - Default value: 0
|
||||||
|
#
|
||||||
|
# 3DS/Wii U/Switch:
|
||||||
|
# - TITLE: Optional; Formal application title, used in metadata.
|
||||||
|
# - Default value: NAME stripped of spaces.
|
||||||
|
# - AUTHOR: Optional; Application author.
|
||||||
|
# - Default value: "Unknown"
|
||||||
|
# - REMOTE_IP: Optional; IP to send executable to when running on hardware. Intended to be set in command line.
|
||||||
|
# - Default value: 127.0.0.1
|
||||||
|
#
|
||||||
|
# 3DS/Wii U:
|
||||||
|
# - DESCRIPTION: Optional; Application description.
|
||||||
|
# - Default value: "No description."
|
||||||
|
#
|
||||||
|
# 3DS:
|
||||||
|
# - PRODUCT_CODE: CIA/3DS product code.
|
||||||
|
# - UNIQUE_ID: CIA/3DS unique ID.
|
||||||
|
# - BANNER_AUDIO: Audio file to use in the CIA/3DS banner.
|
||||||
|
# - Supported file types: WAV, CWAV
|
||||||
|
# - BANNER_IMAGE: Graphics to use in the CIA/3DS banner.
|
||||||
|
# - Supported file types: 256x128 PNG, CGFX
|
||||||
|
# - ICON: Application icon.
|
||||||
|
# - Supported file types: 48x48 PNG
|
||||||
|
# - Category: Optional; CIA/3DS category.
|
||||||
|
# - Supported values: Application, SystemApplication, Applet, Firmware, Base, DlpChild, Demo, Contents, SystemContents, SharedContents, AddOnContents, Patch, AutoUpdateContents
|
||||||
|
# - Default value: Application
|
||||||
|
# - USE_ON_SD: Optional; Whether the CIA/3DS should be installed to the SD card.
|
||||||
|
# - Supported values: true, false
|
||||||
|
# - Default value: true
|
||||||
|
# - MEMORY_TYPE: Optional; CIA/3DS application memory layout.
|
||||||
|
# - Supported values: Application, System, Base
|
||||||
|
# - Default value: Application
|
||||||
|
# - SYSTEM_MODE: Optional; CIA/3DS legacy system mode.
|
||||||
|
# - Supported values: 32MB, 64MB, 72MB, 80MB, 96MB
|
||||||
|
# - Default value: 64MB
|
||||||
|
# - SYSTEM_MODE_EXT: Optional; CIA/3DS extended system mode.
|
||||||
|
# - Supported values: Legacy, 124MB, 178MB
|
||||||
|
# - Default value: Legacy
|
||||||
|
# - CPU_MODE: Optional; CIA/3DS CPU frequency. 804MHz is N3DS-only.
|
||||||
|
# - Supported values: 268MHz, 804MHz
|
||||||
|
# - Default value: 268MHz
|
||||||
|
# - ENABLE_L2_CACHE: Optional; Whether the CIA/3DS should use the N3DS L2 cache.
|
||||||
|
# - Supported values: true, false
|
||||||
|
# - Default value: false
|
||||||
|
# - ICON_FLAGS: Optional; Flags to pass to bannertool when making an SMDH icon.
|
||||||
|
# - ROMFS_DIR: Optional; Directory containing RomFS files.
|
||||||
|
# - LOGO: Optional; Logo animation to use when launching the CIA/3DS.
|
||||||
|
# - Supported file types: BCMA.LZ
|
||||||
|
#
|
||||||
|
# Wii U:
|
||||||
|
# - ICON: Application icon.
|
||||||
|
# - Supported file types: 256x96 PNG
|
||||||
|
# - LONG_DESCRIPTION: Optional; Long version of the description field.
|
||||||
|
# - Default value: Value of DESCRIPTION.
|
||||||
|
#
|
||||||
|
# Switch:
|
||||||
|
# - TITLE_ID: Optional; Application title ID.
|
||||||
|
# - ICON: Optional; Application icon.
|
||||||
|
# - Supported file types: 256x256 JPEG
|
||||||
|
|
||||||
|
# PROLOGUE #
|
||||||
|
|
||||||
|
TARGET ?= NATIVE
|
||||||
|
LIBRARY ?= 0
|
||||||
|
|
||||||
|
ALL_PC_TARGETS := WIN32 WIN64 MAC32 MAC64 LINUX32 LINUX64
|
||||||
|
ALL_SPECIFIC_TARGETS := $(ALL_PC_TARGETS) 3DS WIIU SWITCH
|
||||||
|
ALL_TARGETS := NATIVE NATIVE32 NATIVE64 $(ALL_SPECIFIC_TARGETS)
|
||||||
|
|
||||||
|
TARGETS :=
|
||||||
|
|
||||||
|
ifneq (1,$(words $(TARGET)))
|
||||||
|
TARGETS := $(TARGET)
|
||||||
|
else ifeq ($(TARGET),ALL)
|
||||||
|
TARGETS := $(ALL_SPECIFIC_TARGETS)
|
||||||
|
else ifeq ($(TARGET),PC)
|
||||||
|
TARGETS := $(ALL_PC_TARGETS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(TARGETS),)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
all:
|
||||||
|
@$(foreach target,$(TARGETS),make --no-print-directory TARGET=$(target);)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
$(info Building for $(TARGET)...)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),$(filter $(TARGET),3DS WIIU SWITCH))
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro")
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# TOOLS #
|
||||||
|
|
||||||
|
BUILDTOOLS_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||||
|
|
||||||
|
define createdirrule
|
||||||
|
$(1): | $(dir $(1))
|
||||||
|
|
||||||
|
ifndef $(dir $(1))_DIRECTORY_RULE_IS_DEFINED
|
||||||
|
$(dir $(1)):
|
||||||
|
@mkdir -p $$@
|
||||||
|
|
||||||
|
$(dir $(1))_DIRECTORY_RULE_IS_DEFINED := 1
|
||||||
|
endif
|
||||||
|
endef
|
||||||
|
|
||||||
|
rwildcard=$(wildcard $1/$2) $(foreach d,$(wildcard $1/*),$(call rwildcard,$d,$2))
|
||||||
|
|
||||||
|
# INITIAL COMMON SETUP #
|
||||||
|
|
||||||
|
EMPTY :=
|
||||||
|
SPACE := $(EMPTY) $(EMPTY)
|
||||||
|
STRIPPED_NAME := $(subst $(SPACE),,$(NAME))
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
HOST_OS := windows
|
||||||
|
ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
|
||||||
|
HOST_ARCH := x86_64
|
||||||
|
else
|
||||||
|
HOST_ARCH := i686
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
HOST_OS := mac
|
||||||
|
else ifeq ($(UNAME_S),Linux)
|
||||||
|
HOST_OS := linux
|
||||||
|
else
|
||||||
|
$(error "Unsupported host OS.")
|
||||||
|
endif
|
||||||
|
|
||||||
|
UNAME_M := $(shell uname -m)
|
||||||
|
ifeq ($(UNAME_M),$(filter $(UNAME_M),x86_64 amd64))
|
||||||
|
HOST_ARCH := x86_64
|
||||||
|
else ifeq ($(UNAME_M),$(filter $(UNAME_M),i386 i686))
|
||||||
|
HOST_ARCH := i686
|
||||||
|
else
|
||||||
|
$(error "Unsupported host architecture.")
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),NATIVE)
|
||||||
|
TARGET_OS := $(HOST_OS)
|
||||||
|
TARGET_ARCH := $(HOST_ARCH)
|
||||||
|
else ifeq ($(TARGET),NATIVE32)
|
||||||
|
TARGET_OS := $(HOST_OS)
|
||||||
|
TARGET_ARCH := i686
|
||||||
|
else ifeq ($(TARGET),NATIVE64)
|
||||||
|
TARGET_OS := $(HOST_OS)
|
||||||
|
TARGET_ARCH := x86_64
|
||||||
|
else ifeq ($(TARGET),WIN32)
|
||||||
|
TARGET_OS := windows
|
||||||
|
TARGET_ARCH := i686
|
||||||
|
else ifeq ($(TARGET),WIN64)
|
||||||
|
TARGET_OS := windows
|
||||||
|
TARGET_ARCH := x86_64
|
||||||
|
else ifeq ($(TARGET),LINUX32)
|
||||||
|
TARGET_OS := linux
|
||||||
|
TARGET_ARCH := i686
|
||||||
|
else ifeq ($(TARGET),LINUX64)
|
||||||
|
TARGET_OS := linux
|
||||||
|
TARGET_ARCH := x86_64
|
||||||
|
else ifeq ($(TARGET),MAC32)
|
||||||
|
TARGET_OS := mac
|
||||||
|
TARGET_ARCH := i686
|
||||||
|
else ifeq ($(TARGET),MAC64)
|
||||||
|
TARGET_OS := mac
|
||||||
|
TARGET_ARCH := x86_64
|
||||||
|
else ifeq ($(TARGET),3DS)
|
||||||
|
TARGET_OS := 3ds
|
||||||
|
TARGET_ARCH := arm
|
||||||
|
else ifeq ($(TARGET),WIIU)
|
||||||
|
TARGET_OS := wiiu
|
||||||
|
TARGET_ARCH := ppc
|
||||||
|
else ifeq ($(TARGET),SWITCH)
|
||||||
|
TARGET_OS := switch
|
||||||
|
TARGET_ARCH := aarch64
|
||||||
|
else
|
||||||
|
$(error "Unknown target. Supported targets: $(ALL_TARGETS)")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TARGET_BUILD_DIR := $(BUILD_DIR)/$(TARGET_OS)-$(TARGET_ARCH)
|
||||||
|
TARGET_OUTPUT_DIR := $(OUTPUT_DIR)/$(TARGET_OS)-$(TARGET_ARCH)
|
||||||
|
|
||||||
|
BUILT_FILTER := $(patsubst %.bin,$(TARGET_BUILD_DIR)/%.bin.o,$(BUILD_FILTER)) \
|
||||||
|
$(patsubst %.c,$(TARGET_BUILD_DIR)/%.o,$(BUILD_FILTER)) \
|
||||||
|
$(patsubst %.cpp,$(TARGET_BUILD_DIR)/%.o,$(BUILD_FILTER)) \
|
||||||
|
$(patsubst %.s,$(TARGET_BUILD_DIR)/%.o,$(BUILD_FILTER))
|
||||||
|
|
||||||
|
OBJECT_FILES := $(foreach dir,$(SOURCE_DIRS), \
|
||||||
|
$(patsubst %.bin,$(TARGET_BUILD_DIR)/%.bin.o,$(call rwildcard,$(dir),*.bin)) \
|
||||||
|
$(patsubst %.c,$(TARGET_BUILD_DIR)/%.o,$(call rwildcard,$(dir),*.c)) \
|
||||||
|
$(patsubst %.cpp,$(TARGET_BUILD_DIR)/%.o,$(call rwildcard,$(dir),*.cpp)) \
|
||||||
|
$(patsubst %.s,$(TARGET_BUILD_DIR)/%.o,$(call rwildcard,$(dir),*.s)) \
|
||||||
|
)
|
||||||
|
|
||||||
|
OBJECT_FILES := $(filter-out $(BUILT_FILTER),$(OBJECT_FILES))
|
||||||
|
|
||||||
|
OUTPUT_ZIP_FILE ?= $(OUTPUT_DIR)/$(STRIPPED_NAME).zip
|
||||||
|
|
||||||
|
ifeq ($(strip $(VERSION_MAJOR)),)
|
||||||
|
VERSION_MAJOR := 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(VERSION_MINOR)),)
|
||||||
|
VERSION_MINOR := 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(VERSION_MICRO)),)
|
||||||
|
VERSION_MICRO := 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
LD_FLAGS := $(patsubst %,-L%/lib,$(LIBRARY_DIRS)) $(patsubst %,-l%,$(LIBRARIES)) -Wl,-Map,MyApp.map
|
||||||
|
COMMON_CC_FLAGS := $(sort $(foreach dir,$(SOURCE_DIRS),$(patsubst %,-I$(TARGET_BUILD_DIR)/%,$(dir $(call rwildcard,$(dir),*))))) $(patsubst %,-I%,$(INCLUDE_DIRS)) $(patsubst %,-I%/include,$(LIBRARY_DIRS)) -g -Wall -DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) -DVERSION_MICRO=$(VERSION_MICRO) $(BUILD_FLAGS)
|
||||||
|
COMMON_CXX_FLAGS :=
|
||||||
|
|
||||||
|
ifeq ($(findstring -O,$(BUILD_FLAGS)),)
|
||||||
|
COMMON_CC_FLAGS += -O2
|
||||||
|
endif
|
||||||
|
|
||||||
|
# COMMON LIBRARY SETUP #
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
STRIPPED_NAME := lib$(STRIPPED_NAME)
|
||||||
|
EXTRA_OUTPUT_FILES += $(INCLUDE_DIRS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# TARGET SETUP #
|
||||||
|
|
||||||
|
REMOTE_IP ?= 127.0.0.1 # User-defined
|
||||||
|
|
||||||
|
TITLE ?= $(NAME)
|
||||||
|
AUTHOR ?= "Unknown"
|
||||||
|
DESCRIPTION ?= "No description."
|
||||||
|
LONG_DESCRIPTION ?= $(DESCRIPTION)
|
||||||
|
|
||||||
|
ifeq ($(TARGET_OS),windows)
|
||||||
|
ifeq ($(HOST_OS),windows)
|
||||||
|
AR := ar
|
||||||
|
AS := as
|
||||||
|
CC := gcc
|
||||||
|
CXX := g++
|
||||||
|
else ifeq ($(TARGET_ARCH),i686)
|
||||||
|
AR := i686-w64-mingw32-ar
|
||||||
|
AS := i686-w64-mingw32-as
|
||||||
|
CC := i686-w64-mingw32-gcc
|
||||||
|
CXX := i686-w64-mingw32-g++
|
||||||
|
else ifeq ($(TARGET_ARCH),x86_64)
|
||||||
|
AR := x86_64-w64-mingw32-ar
|
||||||
|
AS := x86_64-w64-mingw32-as
|
||||||
|
CC := x86_64-w64-mingw32-gcc
|
||||||
|
CXX := x86_64-w64-mingw32-g++
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH),i686)
|
||||||
|
COMMON_CC_FLAGS += -m32
|
||||||
|
else ifeq ($(TARGET_ARCH),x86_64)
|
||||||
|
COMMON_CC_FLAGS += -m64
|
||||||
|
endif
|
||||||
|
|
||||||
|
LD_FLAGS += -static-libstdc++ -static-libgcc -static
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).dll
|
||||||
|
COMMON_CC_FLAGS += -fPIC
|
||||||
|
else
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).exe
|
||||||
|
endif
|
||||||
|
else ifeq ($(TARGET_OS),mac)
|
||||||
|
ifeq ($(HOST_OS),mac)
|
||||||
|
AR := ar
|
||||||
|
AS := as
|
||||||
|
CC := gcc
|
||||||
|
CXX := g++
|
||||||
|
else ifeq ($(TARGET_ARCH),i686)
|
||||||
|
AR := i386-apple-darwin15-ar
|
||||||
|
AS := i386-apple-darwin15-as
|
||||||
|
CC := i386-apple-darwin15-gcc
|
||||||
|
CXX := i386-apple-darwin15-g++
|
||||||
|
else ifeq ($(TARGET_ARCH),x86_64)
|
||||||
|
AR := x86_64-apple-darwin15-ar
|
||||||
|
AS := x86_64-apple-darwin15-as
|
||||||
|
CC := x86_64-apple-darwin15-gcc
|
||||||
|
CXX := x86_64-apple-darwin15-g++
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH),i686)
|
||||||
|
COMMON_CC_FLAGS += -m32
|
||||||
|
else ifeq ($(TARGET_ARCH),x86_64)
|
||||||
|
COMMON_CC_FLAGS += -m64
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).so $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).dylib
|
||||||
|
COMMON_CC_FLAGS += -fPIC
|
||||||
|
else
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME)
|
||||||
|
endif
|
||||||
|
else ifeq ($(TARGET_OS),linux)
|
||||||
|
ifeq ($(HOST_OS),linux)
|
||||||
|
AR := ar
|
||||||
|
AS := as
|
||||||
|
CC := gcc
|
||||||
|
CXX := g++
|
||||||
|
else ifeq ($(TARGET_ARCH),i686)
|
||||||
|
AR := i686-pc-linux-gnu-ar
|
||||||
|
AS := i686-pc-linux-gnu-as
|
||||||
|
CC := i686-pc-linux-gnu-gcc
|
||||||
|
CXX := i686-pc-linux-gnu-g++
|
||||||
|
else ifeq ($(TARGET_ARCH),x86_64)
|
||||||
|
AR := x86_64-pc-linux-gnu-ar
|
||||||
|
AS := x86_64-pc-linux-gnu-as
|
||||||
|
CC := x86_64-pc-linux-gnu-gcc
|
||||||
|
CXX := x86_64-pc-linux-gnu-g++
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH),i686)
|
||||||
|
COMMON_CC_FLAGS += -m32
|
||||||
|
else ifeq ($(TARGET_ARCH),x86_64)
|
||||||
|
COMMON_CC_FLAGS += -m64
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).so
|
||||||
|
COMMON_CC_FLAGS += -fPIC
|
||||||
|
else
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME)
|
||||||
|
endif
|
||||||
|
else ifeq ($(TARGET_OS),3ds)
|
||||||
|
BUILT_FILTER := $(patsubst %.v.pica,$(TARGET_BUILD_DIR)/%.shbin.o,$(BUILD_FILTER)) \
|
||||||
|
$(patsubst %.shlist,$(TARGET_BUILD_DIR)/%.shbin.o,$(BUILD_FILTER)) \
|
||||||
|
|
||||||
|
OBJECT_FILES := $(foreach dir,$(SOURCE_DIRS), \
|
||||||
|
$(patsubst %.v.pica,$(TARGET_BUILD_DIR)/%.shbin.o,$(call rwildcard,$(dir),*.v.pica)) \
|
||||||
|
$(patsubst %.shlist,$(TARGET_BUILD_DIR)/%.shbin.o,$(call rwildcard,$(dir),*.shlist)) \
|
||||||
|
) $(OBJECT_FILES)
|
||||||
|
|
||||||
|
OBJECT_FILES := $(filter-out $(BUILT_FILTER),$(OBJECT_FILES))
|
||||||
|
|
||||||
|
DEVKITARM := $(DEVKITPRO)/devkitARM
|
||||||
|
|
||||||
|
AR := $(DEVKITARM)/bin/arm-none-eabi-ar
|
||||||
|
AS := $(DEVKITARM)/bin/arm-none-eabi-as
|
||||||
|
CC := $(DEVKITARM)/bin/arm-none-eabi-gcc
|
||||||
|
CXX := $(DEVKITARM)/bin/arm-none-eabi-g++
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a
|
||||||
|
else
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).elf $(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/$(STRIPPED_NAME).3dsx $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).3ds $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).cia
|
||||||
|
endif
|
||||||
|
|
||||||
|
LD_FLAGS += -specs=3dsx.specs
|
||||||
|
COMMON_CC_FLAGS += -mword-relocations -ffast-math -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -D__3DS__
|
||||||
|
|
||||||
|
SERVEFILES := python $(BUILDTOOLS_DIR)/3ds/servefiles.py
|
||||||
|
|
||||||
|
CATEGORY ?= Application
|
||||||
|
USE_ON_SD ?= true
|
||||||
|
MEMORY_TYPE ?= Application
|
||||||
|
SYSTEM_MODE ?= 64MB
|
||||||
|
SYSTEM_MODE_EXT ?= Legacy
|
||||||
|
CPU_SPEED ?= 268MHz
|
||||||
|
ENABLE_L2_CACHE ?= false
|
||||||
|
|
||||||
|
_3DSXTOOL_FLAGS :=
|
||||||
|
COMMON_MAKEROM_FLAGS := -rsf $(BUILDTOOLS_DIR)/3ds/template.rsf -target t -exefslogo -icon $(TARGET_BUILD_DIR)/icon.icn -banner $(TARGET_BUILD_DIR)/banner.bnr -major $(VERSION_MAJOR) -minor $(VERSION_MINOR) -micro $(VERSION_MICRO) -DAPP_TITLE="$(TITLE)" -DAPP_PRODUCT_CODE="$(PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(UNIQUE_ID)" -DAPP_SYSTEM_MODE="$(SYSTEM_MODE)" -DAPP_SYSTEM_MODE_EXT="$(SYSTEM_MODE_EXT)" -DAPP_CATEGORY="$(CATEGORY)" -DAPP_USE_ON_SD="$(USE_ON_SD)" -DAPP_MEMORY_TYPE="$(MEMORY_TYPE)" -DAPP_CPU_SPEED="$(CPU_SPEED)" -DAPP_ENABLE_L2_CACHE="$(ENABLE_L2_CACHE)" -DAPP_VERSION_MAJOR="$(VERSION_MAJOR)"
|
||||||
|
|
||||||
|
ifneq ("$(wildcard $(ROMFS_DIR))","")
|
||||||
|
_3DSXTOOL_FLAGS += --romfs=$(ROMFS_DIR)
|
||||||
|
COMMON_MAKEROM_FLAGS += -DAPP_ROMFS="$(ROMFS_DIR)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ("$(wildcard $(LOGO))","")
|
||||||
|
COMMON_MAKEROM_FLAGS += -logo "$(LOGO)"
|
||||||
|
else ifneq ($(LOGO),plain)
|
||||||
|
COMMON_MAKEROM_FLAGS += -logo "$(BUILDTOOLS_DIR)/3ds/logo.bcma.lz"
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(suffix $(BANNER_IMAGE)),.cgfx)
|
||||||
|
BANNER_IMAGE_ARG := -ci
|
||||||
|
else
|
||||||
|
BANNER_IMAGE_ARG := -i
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(suffix $(BANNER_AUDIO)),.cwav)
|
||||||
|
BANNER_AUDIO_ARG := -ca
|
||||||
|
else
|
||||||
|
BANNER_AUDIO_ARG := -a
|
||||||
|
endif
|
||||||
|
else ifeq ($(TARGET_OS),wiiu)
|
||||||
|
DEVKITPPC := $(DEVKITPRO)/devkitPPC
|
||||||
|
|
||||||
|
AR := $(DEVKITPPC)/bin/powerpc-eabi-ar
|
||||||
|
AS := $(DEVKITPPC)/bin/powerpc-eabi-as
|
||||||
|
CC := $(DEVKITPPC)/bin/powerpc-eabi-gcc
|
||||||
|
CXX := $(DEVKITPPC)/bin/powerpc-eabi-g++
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a
|
||||||
|
else
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/$(STRIPPED_NAME).elf $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/icon.png
|
||||||
|
endif
|
||||||
|
|
||||||
|
LD_FLAGS += -Wl,-d,--gc-sections
|
||||||
|
COMMON_CC_FLAGS += -mwup -mcpu=750 -meabi -mhard-float -ffast-math -DESPRESSO -DWIIU
|
||||||
|
else ifeq ($(TARGET_OS),switch)
|
||||||
|
DEVKITA64 := $(DEVKITPRO)/devkitA64
|
||||||
|
|
||||||
|
AR := $(DEVKITA64)/bin/aarch64-none-elf-ar
|
||||||
|
AS := $(DEVKITA64)/bin/aarch64-none-elf-as
|
||||||
|
CC := $(DEVKITA64)/bin/aarch64-none-elf-gcc
|
||||||
|
CXX := $(DEVKITA64)/bin/aarch64-none-elf-g++
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a
|
||||||
|
else
|
||||||
|
OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).elf $(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/$(STRIPPED_NAME).nro
|
||||||
|
endif
|
||||||
|
|
||||||
|
LD_FLAGS += -specs=$(DEVKITPRO)/libnx/switch.specs
|
||||||
|
COMMON_CC_FLAGS += -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -D__SWITCH__
|
||||||
|
COMMON_CXX_FLAGS += -fno-rtti -fno-exceptions
|
||||||
|
|
||||||
|
NRO_FLAGS :=
|
||||||
|
|
||||||
|
ifneq ("$(wildcard $(ICON))","")
|
||||||
|
NRO_FLAGS += --icon=$(ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
NACP_FLAGS :=
|
||||||
|
|
||||||
|
ifneq ($(TITLE_ID),)
|
||||||
|
NACP_FLAGS += --titleid=$(TITLE_ID)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# FINAL COMMON SETUP #
|
||||||
|
|
||||||
|
CLANG_CC := $(subst gcc,clang,$(CC))
|
||||||
|
CLANG_CC_EXISTS := $(shell which $(CLANG_CC) > /dev/null 2> /dev/null; echo $$?)
|
||||||
|
ifeq ($(CLANG_CC_EXISTS),0)
|
||||||
|
CC := $(CLANG_CC)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CLANG_CXX := $(subst g++,clang++,$(CXX))
|
||||||
|
CLANG_CXX_EXISTS := $(shell which $(CLANG_CXX) > /dev/null 2> /dev/null; echo $$?)
|
||||||
|
ifeq ($(CLANG_CXX_EXISTS),0)
|
||||||
|
CXX := $(CLANG_CXX)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CC_FLAGS := $(COMMON_CC_FLAGS) $(BUILD_FLAGS_CC)
|
||||||
|
CXX_FLAGS := $(COMMON_CC_FLAGS) $(COMMON_CXX_FLAGS) $(BUILD_FLAGS_CXX)
|
||||||
|
|
||||||
|
ifeq ($(findstring -std,$(BUILD_FLAGS_CC)),)
|
||||||
|
CC_FLAGS += -std=gnu11
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(findstring -std,$(BUILD_FLAGS_CXX)),)
|
||||||
|
CXX_FLAGS += -std=gnu++11
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(EXTRA_OUTPUT_FILES),)
|
||||||
|
EXTRA_OUTPUT_COPY_CMD := cp -r $(EXTRA_OUTPUT_FILES) $(OUTPUT_DIR)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# MAIN RULES #
|
||||||
|
|
||||||
|
.PHONY: all run install clean
|
||||||
|
|
||||||
|
all: $(OUTPUT_ZIP_FILE)
|
||||||
|
|
||||||
|
# TARGET RULES #
|
||||||
|
|
||||||
|
ifeq ($(TARGET_OS),3ds)
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
|
||||||
|
install: $(OUTPUT_ZIP_FILE)
|
||||||
|
@mkdir -p $(DEVKITPRO)/$(STRIPPED_NAME)
|
||||||
|
@cp -r $(TARGET_OUTPUT_DIR)/* $(DEVKITPRO)/$(STRIPPED_NAME)
|
||||||
|
@echo "Installed."
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
run: $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@citra $(RUN_FLAGS) $(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/$(STRIPPED_NAME).3dsx
|
||||||
|
|
||||||
|
runhw: $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@3dslink --address $(REMOTE_IP) $(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/$(STRIPPED_NAME).3dsx
|
||||||
|
|
||||||
|
install: $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Installing..."
|
||||||
|
@$(SERVEFILES) $(REMOTE_IP) $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).cia
|
||||||
|
@echo "Installed."
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.shbin.o: $(TARGET_BUILD_DIR)/%.shbin.c
|
||||||
|
@echo $@
|
||||||
|
@$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@
|
||||||
|
|
||||||
|
define shader-as
|
||||||
|
$(eval CURBIN := $(patsubst %.shbin.c,%.shbin,$@))
|
||||||
|
@picasso -o $(CURBIN) $1
|
||||||
|
@cd $(dir $(CURBIN)); \
|
||||||
|
xxd -i $(notdir $(CURBIN)) "$(CURDIR)/$@"
|
||||||
|
echo "extern const u8" `(echo $(notdir $(CURBIN)) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
|
||||||
|
echo "extern const u32" `(echo $(notdir $(CURBIN)) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_len";" >> `(echo $(CURBIN) | tr . _)`.h
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.shbin.c: %.v.pica %.g.pica
|
||||||
|
@echo $@
|
||||||
|
@$(call shader-as,$^)
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.shbin.c: %.v.pica
|
||||||
|
@echo $@
|
||||||
|
@$(call shader-as,$<)
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.shbin.c: %.shlist
|
||||||
|
@echo $@
|
||||||
|
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file)))
|
||||||
|
|
||||||
|
%.bnr: $(BANNER_IMAGE) $(BANNER_AUDIO)
|
||||||
|
@echo $@
|
||||||
|
@bannertool makebanner $(BANNER_IMAGE_ARG) $(BANNER_IMAGE) $(BANNER_AUDIO_ARG) $(BANNER_AUDIO) -o $@ > /dev/null
|
||||||
|
|
||||||
|
%.icn: $(ICON)
|
||||||
|
@echo $@
|
||||||
|
@bannertool makesmdh -s "$(TITLE)" -l "$(TITLE) - $(DESCRIPTION)" -p "$(AUTHOR)" -i $(ICON) $(ICON_FLAGS) -o $@ > /dev/null
|
||||||
|
|
||||||
|
%.smdh: $(ICON)
|
||||||
|
@echo $@
|
||||||
|
@smdhtool --create "$(TITLE)" "$(DESCRIPTION)" "$(AUTHOR)" $(ICON) $@
|
||||||
|
|
||||||
|
$(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/%.3dsx: $(TARGET_OUTPUT_DIR)/%.elf $(TARGET_BUILD_DIR)/meta.smdh
|
||||||
|
@echo $@
|
||||||
|
@3dsxtool $< $@ --smdh=$(word 2,$^) $(_3DSXTOOL_FLAGS)
|
||||||
|
|
||||||
|
%.3ds: %.elf $(TARGET_BUILD_DIR)/banner.bnr $(TARGET_BUILD_DIR)/icon.icn
|
||||||
|
@echo $@
|
||||||
|
@makerom -f cci -o $@ -elf $< -DAPP_ENCRYPTED=true $(COMMON_MAKEROM_FLAGS)
|
||||||
|
|
||||||
|
%.cia: %.elf $(TARGET_BUILD_DIR)/banner.bnr $(TARGET_BUILD_DIR)/icon.icn
|
||||||
|
@echo $@
|
||||||
|
@makerom -f cia -o $@ -elf $< -DAPP_ENCRYPTED=false $(COMMON_MAKEROM_FLAGS)
|
||||||
|
|
||||||
|
else ifeq ($(TARGET_OS),wiiu)
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
|
||||||
|
install: $(OUTPUT_ZIP_FILE)
|
||||||
|
@mkdir -p $(DEVKITPRO)/$(STRIPPED_NAME)
|
||||||
|
@cp -r $(TARGET_OUTPUT_DIR)/* $(DEVKITPRO)/$(STRIPPED_NAME)
|
||||||
|
@echo "Installed."
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
runhw: $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@WIILOAD=tcp:$(REMOTE_IP) wiiload $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/$(STRIPPED_NAME).elf $(RUN_FLAGS)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml:
|
||||||
|
@echo $@
|
||||||
|
@cp $(BUILDTOOLS_DIR)/wiiu/meta_template.xml $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml
|
||||||
|
@sed -i -- 's/$$(TITLE)/$(subst /,\/,$(TITLE))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml
|
||||||
|
@sed -i -- 's/$$(AUTHOR)/$(subst /,\/,$(AUTHOR))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml
|
||||||
|
@sed -i -- 's/$$(VERSION)/$(subst /,\/,$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_MICRO))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml
|
||||||
|
@sed -i -- 's/$$(RELEASE_DATE)/$(subst /,\/,$(shell date +'%Y%m%d%H%M%S'))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml
|
||||||
|
@sed -i -- 's/$$(SHORT_DESCRIPTION)/$(subst /,\/,$(DESCRIPTION))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml
|
||||||
|
@sed -i -- 's/$$(LONG_DESCRIPTION)/$(subst /,\/,$(LONG_DESCRIPTION))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml
|
||||||
|
|
||||||
|
$(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/icon.png:
|
||||||
|
@echo $@
|
||||||
|
@cp $(ICON) $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/icon.png
|
||||||
|
|
||||||
|
else ifeq ($(TARGET_OS),switch)
|
||||||
|
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
|
||||||
|
install: $(OUTPUT_ZIP_FILE)
|
||||||
|
@mkdir -p $(DEVKITPRO)/$(STRIPPED_NAME)
|
||||||
|
@cp -r $(TARGET_OUTPUT_DIR)/* $(DEVKITPRO)/$(STRIPPED_NAME)
|
||||||
|
@echo "Installed."
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
run: $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@yuzu-cmd $(RUN_FLAGS) $(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/$(STRIPPED_NAME).nro
|
||||||
|
|
||||||
|
runhw: $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@nxlink --address $(REMOTE_IP) $(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/$(STRIPPED_NAME).nro
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
%.nacp:
|
||||||
|
@echo $@
|
||||||
|
@nacptool --create "$(TITLE)" "$(AUTHOR)" "$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_MICRO)" $@ $(NACP_FLAGS)
|
||||||
|
|
||||||
|
$(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/%.nro: $(TARGET_OUTPUT_DIR)/%.elf $(TARGET_BUILD_DIR)/meta.nacp
|
||||||
|
@echo $@
|
||||||
|
@elf2nro $< $@ --nacp=$(word 2,$^) $(NRO_FLAGS)
|
||||||
|
|
||||||
|
else ifeq ($(TARGET_OS),windows)
|
||||||
|
ifeq ($(HOST_OS),$(filter $(HOST_OS),linux mac))
|
||||||
|
ifneq ($(LIBRARY),1)
|
||||||
|
|
||||||
|
run: $(OUTPUT_FILES) $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@wine ./$< $(RUN_FLAGS)
|
||||||
|
|
||||||
|
endif
|
||||||
|
else ifeq ($(HOST_OS),windows)
|
||||||
|
ifneq ($(LIBRARY),1)
|
||||||
|
|
||||||
|
run: $(OUTPUT_FILES) $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@./$< $(RUN_FLAGS)
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else ifeq ($(TARGET_OS),$(filter $(TARGET_OS),mac linux))
|
||||||
|
ifeq ($(HOST_OS),$(TARGET_OS))
|
||||||
|
ifeq ($(LIBRARY),1)
|
||||||
|
|
||||||
|
install: $(OUTPUT_ZIP_FILE)
|
||||||
|
@install -m 0755 $(OUTPUT_FILES) /usr/local/lib
|
||||||
|
@install -m 0644 $(foreach dir,$(INCLUDE_DIRS),$(wildcard $(dir)/*)) /usr/local/include
|
||||||
|
@echo "Installed."
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
run: $(OUTPUT_FILES) $(OUTPUT_ZIP_FILE)
|
||||||
|
@echo "Running..."
|
||||||
|
@./$< $(RUN_FLAGS)
|
||||||
|
|
||||||
|
install: $(OUTPUT_ZIP_FILE)
|
||||||
|
@install -m 0755 $(OUTPUT_FILES) /usr/local/bin
|
||||||
|
@echo "Installed."
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# COMMON RULES #
|
||||||
|
|
||||||
|
$(OUTPUT_ZIP_FILE): $(OUTPUT_FILES) $(EXTRA_OUTPUT_FILES)
|
||||||
|
|
||||||
|
$(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME): $(OBJECT_FILES)
|
||||||
|
@echo $@
|
||||||
|
@$(CXX) $(CXX_FLAGS) $^ -o $@ $(LD_FLAGS)
|
||||||
|
|
||||||
|
%.elf: $(OBJECT_FILES)
|
||||||
|
@echo $@
|
||||||
|
@$(CXX) $(CXX_FLAGS) $^ -o $@ $(LD_FLAGS)
|
||||||
|
|
||||||
|
%.a: $(OBJECT_FILES)
|
||||||
|
@echo $@
|
||||||
|
@$(AR) -rc $@ $^
|
||||||
|
|
||||||
|
%.so: $(OBJECT_FILES)
|
||||||
|
@echo $@
|
||||||
|
@$(CXX) $(CXX_FLAGS) -shared $^ -o $@ $(LD_FLAGS)
|
||||||
|
|
||||||
|
%.exe: $(OBJECT_FILES)
|
||||||
|
@echo $@
|
||||||
|
@$(CXX) $(CXX_FLAGS) $^ -o $@ $(LD_FLAGS)
|
||||||
|
|
||||||
|
%.dll: $(OBJECT_FILES)
|
||||||
|
@echo $@
|
||||||
|
@$(CXX) $(CXX_FLAGS) -shared $^ -o $@ $(LD_FLAGS)
|
||||||
|
|
||||||
|
%.dylib: $(OBJECT_FILES)
|
||||||
|
@echo $@
|
||||||
|
@$(CXX) $(CXX_FLAGS) -dynamiclib -undefined suppress -flat_namespace $^ -o $@ $(LD_FLAGS)
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.o: %.c
|
||||||
|
@echo $@
|
||||||
|
@$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.o: %.cpp
|
||||||
|
@echo $@
|
||||||
|
@$(CXX) -c $(CXX_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.o: %.s
|
||||||
|
@echo $@
|
||||||
|
@$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d -x assembler-with-cpp $< -o $@
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.o: %.S
|
||||||
|
@echo $@
|
||||||
|
@$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d -x assembler-with-cpp $< -o $@
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.bin.o: $(TARGET_BUILD_DIR)/%.bin.c
|
||||||
|
@echo $@
|
||||||
|
@$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@
|
||||||
|
|
||||||
|
$(TARGET_BUILD_DIR)/%.bin.c: %.bin
|
||||||
|
@echo $@
|
||||||
|
@cd $(<D); \
|
||||||
|
xxd -i $(<F) "$(CURDIR)/$@"
|
||||||
|
@echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(TARGET_BUILD_DIR)/$< | tr . _)`.h
|
||||||
|
@echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_len";" >> `(echo $(TARGET_BUILD_DIR)/$< | tr . _)`.h
|
||||||
|
|
||||||
|
$(foreach file,$(OBJECT_FILES),$(eval $(call createdirrule,$(file))))
|
||||||
|
$(foreach file,$(OUTPUT_FILES),$(eval $(call createdirrule,$(file))))
|
||||||
|
|
||||||
|
# DEPENDS #
|
||||||
|
|
||||||
|
DEPENDS := $(OBJECT_FILES:.o=.d)
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
# CLEAN #
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf $(BUILD_DIR) $(OUTPUT_DIR)
|
||||||
|
@echo "Cleaned."
|
||||||
9
app/buildtools/wiiu/meta_template.xml
Normal file
9
app/buildtools/wiiu/meta_template.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<app version="1">
|
||||||
|
<name>$(TITLE)</name>
|
||||||
|
<coder>$(AUTHOR)</coder>
|
||||||
|
<version>$(VERSION)</version>
|
||||||
|
<release_date>$(RELEASE_DATE)</release_date>
|
||||||
|
<short_description>$(SHORT_DESCRIPTION)</short_description>
|
||||||
|
<long_description>$(LONG_DESCRIPTION)</long_description>
|
||||||
|
</app>
|
||||||
BIN
app/images/logo.bclim
Normal file
BIN
app/images/logo.bclim
Normal file
Binary file not shown.
68
app/includes/3gx.h
Normal file
68
app/includes/3gx.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "3ds/types.h"
|
||||||
|
|
||||||
|
#define _3GX_MAGIC (0x3230303024584733) /* "3GX$0002" */
|
||||||
|
|
||||||
|
typedef struct CTR_PACKED
|
||||||
|
{
|
||||||
|
u32 authorLen;
|
||||||
|
const char* authorMsg;
|
||||||
|
u32 titleLen;
|
||||||
|
const char* titleMsg;
|
||||||
|
u32 summaryLen;
|
||||||
|
const char* summaryMsg;
|
||||||
|
u32 descriptionLen;
|
||||||
|
const char* descriptionMsg;
|
||||||
|
union {
|
||||||
|
u32 flags;
|
||||||
|
struct {
|
||||||
|
u32 embeddedExeLoadFunc : 1;
|
||||||
|
u32 embeddedSwapSaveLoadFunc : 1;
|
||||||
|
u32 memoryRegionSize : 2;
|
||||||
|
u32 compatibility : 2;
|
||||||
|
u32 eventsSelfManaged : 1;
|
||||||
|
u32 swapNotNeeded : 1;
|
||||||
|
u32 unused : 24;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
u32 exeLoadChecksum;
|
||||||
|
u32 builtInLoadExeArgs[4];
|
||||||
|
u32 builtInSwapSaveLoadArgs[4];
|
||||||
|
} _3gx_Infos;
|
||||||
|
|
||||||
|
typedef struct CTR_PACKED
|
||||||
|
{
|
||||||
|
u32 count;
|
||||||
|
u32 * titles;
|
||||||
|
} _3gx_Targets;
|
||||||
|
|
||||||
|
typedef struct CTR_PACKED
|
||||||
|
{
|
||||||
|
u32 nbSymbols;
|
||||||
|
u32 symbolsOffset;
|
||||||
|
u32 nameTableOffset;
|
||||||
|
} _3gx_Symtable;
|
||||||
|
|
||||||
|
typedef struct CTR_PACKED
|
||||||
|
{
|
||||||
|
u32 codeOffset;
|
||||||
|
u32 rodataOffset;
|
||||||
|
u32 dataOffset;
|
||||||
|
u32 codeSize;
|
||||||
|
u32 rodataSize;
|
||||||
|
u32 dataSize;
|
||||||
|
u32 bssSize;
|
||||||
|
u32 exeLoadFuncOffset; // NOP terminated
|
||||||
|
u32 swapSaveFuncOffset; // NOP terminated
|
||||||
|
u32 swapLoadFuncOffset; // NOP terminated
|
||||||
|
} _3gx_Executable;
|
||||||
|
|
||||||
|
typedef struct CTR_PACKED
|
||||||
|
{
|
||||||
|
u64 magic;
|
||||||
|
u32 version;
|
||||||
|
u32 reserved;
|
||||||
|
_3gx_Infos infos;
|
||||||
|
_3gx_Executable executable;
|
||||||
|
_3gx_Targets targets;
|
||||||
|
_3gx_Symtable symtable;
|
||||||
|
} _3gx_Header;
|
||||||
74
app/includes/BCLIM.hpp
Normal file
74
app/includes/BCLIM.hpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds.h"
|
||||||
|
#include "tuple"
|
||||||
|
#include "CTRPluginFramework/Vector.hpp"
|
||||||
|
#include "CTRPluginFramework/Rect.hpp"
|
||||||
|
#include "CTRPluginFramework/Color.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework {
|
||||||
|
class BCLIM {
|
||||||
|
public:
|
||||||
|
enum class TextureFormat : u32 {
|
||||||
|
L8 = 0,
|
||||||
|
A8 = 1,
|
||||||
|
LA4 = 2,
|
||||||
|
LA8 = 3,
|
||||||
|
HILO8 = 4,
|
||||||
|
RGB565 = 5,
|
||||||
|
RGB8 = 6,
|
||||||
|
RGBA5551 = 7,
|
||||||
|
RGBA4 = 8,
|
||||||
|
RGBA8 = 9,
|
||||||
|
ETC1 = 10,
|
||||||
|
ETC1A4 = 11,
|
||||||
|
L4 = 12,
|
||||||
|
A4 = 13,
|
||||||
|
};
|
||||||
|
struct Header {
|
||||||
|
u32 magic;
|
||||||
|
u16 endian;
|
||||||
|
u16 headerSize;
|
||||||
|
u32 version;
|
||||||
|
u32 fileSize;
|
||||||
|
u32 blockCount;
|
||||||
|
struct {
|
||||||
|
u32 magic;
|
||||||
|
u32 imagHeaderSize;
|
||||||
|
u16 width;
|
||||||
|
u16 height;
|
||||||
|
TextureFormat format;
|
||||||
|
} imag;
|
||||||
|
u32 dataLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
BCLIM(void* bclimData, u32 bclimSize) : BCLIM(bclimData, (Header*)((u32)bclimData + bclimSize - 0x28)) {}
|
||||||
|
BCLIM(void* bclimData, Header* bclimHeader) : data(bclimData), header(bclimHeader) {}
|
||||||
|
|
||||||
|
using ColorBlendCallback = Color(*)(const Color &, const Color &);
|
||||||
|
static std::pair<bool, ColorBlendCallback> OpaqueBlend() {
|
||||||
|
return std::make_pair(false, OpaqueBlendFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
using RenderBackend = void(*)(void*, bool, Color*, int posX, int posY);
|
||||||
|
static std::pair<void*, RenderBackend> RenderInterface() {
|
||||||
|
return std::make_pair(nullptr, RenderInterfaceBackend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(const Rect<int>& position, std::pair<void*, RenderBackend> backend = RenderInterface(), const Rect<int>& crop = Rect<int>(0, 0, INT32_MAX, INT32_MAX), const Rect<int>& limits = Rect<int>(0, 0, 400, 240), std::pair<bool, ColorBlendCallback> colorBlend = OpaqueBlend());
|
||||||
|
|
||||||
|
void* data;
|
||||||
|
private:
|
||||||
|
Header* header;
|
||||||
|
static const u8 textureTileOrder[16];
|
||||||
|
static const u8 etc1Modifiers[8][2];
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T GetDataAt(int offset) {
|
||||||
|
return *(T*)(((u32)data) + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RenderInterfaceBackend(void* usrData, bool isRead, Color* c, int posX, int posY);
|
||||||
|
|
||||||
|
static Color OpaqueBlendFunc(const Color& dst, const Color& src);
|
||||||
|
};
|
||||||
|
}
|
||||||
7
app/includes/CTRPluginFramework/CTRPluginFramework.hpp
Normal file
7
app/includes/CTRPluginFramework/CTRPluginFramework.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CTRPluginFramework/System/Mutex.hpp"
|
||||||
|
#include "CTRPluginFramework/System/Lock.hpp"
|
||||||
|
#include "CTRPluginFramework/Vector.hpp"
|
||||||
|
#include "CTRPluginFramework/Rect.hpp"
|
||||||
|
#include "CTRPluginFramework/Color.hpp"
|
||||||
37
app/includes/CTRPluginFramework/Clock.hpp
Normal file
37
app/includes/CTRPluginFramework/Clock.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds.h"
|
||||||
|
#include "CTRPluginFramework/Time.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Clock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Clock(void) : _startTime(GetCurrentTime()) {}
|
||||||
|
constexpr Clock(const Time& time) : _startTime(time) {}
|
||||||
|
|
||||||
|
__always_inline Time GetElapsedTime(void) const {
|
||||||
|
return (GetCurrentTime() - _startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
__always_inline bool HasTimePassed(const Time& time) const {
|
||||||
|
return (GetElapsedTime() >= time);
|
||||||
|
}
|
||||||
|
|
||||||
|
__always_inline Time Restart(void) {
|
||||||
|
const Time now = GetCurrentTime();
|
||||||
|
|
||||||
|
const Time ret = now - _startTime;
|
||||||
|
|
||||||
|
_startTime = now;
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Time _startTime;
|
||||||
|
|
||||||
|
static __always_inline Time GetCurrentTime(void)
|
||||||
|
{
|
||||||
|
return Ticks(svcGetSystemTick());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
67
app/includes/CTRPluginFramework/Color.hpp
Normal file
67
app/includes/CTRPluginFramework/Color.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds/types.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Color
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum class BlendMode
|
||||||
|
{
|
||||||
|
Alpha,
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Color(void) : a(255), b(0), g(0), r(0) {}
|
||||||
|
constexpr Color(u32 color) : raw(color) {}
|
||||||
|
constexpr Color(u8 red, u8 green, u8 blue, u8 alpha = 255) : a(alpha), b(blue), g(green), r(red) {}
|
||||||
|
|
||||||
|
inline u32 ToU32(void) const { return raw; };
|
||||||
|
Color &Fade(float fading);
|
||||||
|
Color Blend(const Color &color, BlendMode mode) const;
|
||||||
|
|
||||||
|
inline bool operator == (const Color &right) const {return raw == right.raw;}
|
||||||
|
inline bool operator != (const Color &right) const {return raw != right.raw;}
|
||||||
|
bool operator < (const Color &right) const;
|
||||||
|
bool operator <= (const Color &right) const;
|
||||||
|
bool operator > (const Color &right) const;
|
||||||
|
bool operator >= (const Color &right) const;
|
||||||
|
Color operator + (const Color &right) const;
|
||||||
|
Color operator - (const Color &right) const;
|
||||||
|
Color operator * (const Color &right) const;
|
||||||
|
Color &operator += (const Color &right);
|
||||||
|
Color &operator -= (const Color &right);
|
||||||
|
Color &operator *= (const Color &right);
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
char strColor[5] = { 0 };
|
||||||
|
|
||||||
|
strColor[0] = 0x1B;
|
||||||
|
strColor[1] = std::max((u8)1, r);
|
||||||
|
strColor[2] = std::max((u8)1, g);
|
||||||
|
strColor[3] = std::max((u8)1, b);
|
||||||
|
|
||||||
|
return strColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 raw;
|
||||||
|
struct // Match raw byte order
|
||||||
|
{
|
||||||
|
u8 a;
|
||||||
|
u8 b;
|
||||||
|
u8 g;
|
||||||
|
u8 r;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
143
app/includes/CTRPluginFramework/Rect.hpp
Normal file
143
app/includes/CTRPluginFramework/Rect.hpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "CTRPluginFramework/Vector.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class Rect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Rect();
|
||||||
|
Rect(const Vector<T>& leftTop, const Vector<T>& size);
|
||||||
|
Rect(const Vector<T>& leftTop, T width, T height);
|
||||||
|
Rect(T left, T top, const Vector<T>& size);
|
||||||
|
Rect(T left, T top, T width, T height);
|
||||||
|
template <typename U>
|
||||||
|
explicit Rect(const Rect<U>& rect);
|
||||||
|
|
||||||
|
bool Contains(T x, T y) const;
|
||||||
|
bool Contains(const Vector<T>& point) const;
|
||||||
|
bool Intersects(const Rect<T>& rect) const;
|
||||||
|
bool Intersects(const Rect<T>& rect, Rect<T>& intersect) const;
|
||||||
|
|
||||||
|
Vector<T> leftTop;
|
||||||
|
Vector<T> size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect() : leftTop(0, 0), size(0, 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(const Vector<T>& leftTopCorner, const Vector<T>& size)
|
||||||
|
{
|
||||||
|
leftTop = leftTopCorner;
|
||||||
|
this->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(const Vector<T>& leftTopCorner, T width, T height)
|
||||||
|
{
|
||||||
|
leftTop = leftTopCorner;
|
||||||
|
size.x = width;
|
||||||
|
size.y = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(T left, T top, const Vector<T>& size)
|
||||||
|
{
|
||||||
|
leftTop.x = left;
|
||||||
|
leftTop.y = top;
|
||||||
|
this->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(T left, T top, T width, T height)
|
||||||
|
{
|
||||||
|
leftTop.x = left;
|
||||||
|
leftTop.y = top;
|
||||||
|
size.x = width;
|
||||||
|
size.y = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename U>
|
||||||
|
Rect<T>::Rect(const Rect<U>& rect)
|
||||||
|
{
|
||||||
|
leftTop = reinterpret_cast<T>(rect.leftTop);
|
||||||
|
size = reinterpret_cast<T>(rect.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Contains(T x, T y) const
|
||||||
|
{
|
||||||
|
T minX = std::min(leftTop.x, leftTop.x + size.x);
|
||||||
|
T maxX = std::max(leftTop.x, leftTop.x + size.x);
|
||||||
|
T minY = std::min(leftTop.y, leftTop.y + size.y);
|
||||||
|
T maxY = std::max(leftTop.y, leftTop.y + size.y);
|
||||||
|
|
||||||
|
return (x >= minX && x < maxX
|
||||||
|
&& y >= minY && y < maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Contains(const Vector<T>& point) const
|
||||||
|
{
|
||||||
|
return (Contains(point.x, point.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Intersects(const Rect<T>& rect) const
|
||||||
|
{
|
||||||
|
Rect<T> intersect;
|
||||||
|
return (Intersects(rect, intersect));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Intersects(const Rect<T> &rect, Rect<T> &intersect) const
|
||||||
|
{
|
||||||
|
T thisMinX = std::min(leftTop.x, leftTop.x + size.x);
|
||||||
|
T thisMaxX = std::max(leftTop.x, leftTop.x + size.x);
|
||||||
|
T thisMinY = std::min(leftTop.y, leftTop.y + size.y);
|
||||||
|
T thisMaxY = std::max(leftTop.y, leftTop.y + size.y);
|
||||||
|
T rectMinX = std::min(rect.leftTop.x, rect.leftTop.x + rect.size.x);
|
||||||
|
T rectMaxX = std::max(rect.leftTop.x, rect.leftTop.x + rect.size.x);
|
||||||
|
T rectMinY = std::min(rect.leftTop.y, rect.leftTop.y + rect.size.y);
|
||||||
|
T rectMaxY = std::max(rect.leftTop.y, rect.leftTop.y + rect.size.y);
|
||||||
|
|
||||||
|
T intersectLeftX = std::max(thisMinX, rectMinX);
|
||||||
|
T intersectLeftY = std::max(thisMinY, rectMinY);
|
||||||
|
T intersectRightX = std::min(thisMaxX, rectMaxX);
|
||||||
|
T intersectRightY = std::min(thisMaxY, rectMaxY);
|
||||||
|
|
||||||
|
if (intersectLeftX < intersectRightX && intersectLeftY < intersectRightY)
|
||||||
|
{
|
||||||
|
intersect = Rect<T>(intersectLeftX, intersectLeftY, intersectRightX - intersectLeftX,
|
||||||
|
intersectRightY - intersectLeftY);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
intersect = Rect<T>(0, 0, 0, 0);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator ==(Rect<T> &left, Rect<T> &right)
|
||||||
|
{
|
||||||
|
return (left.leftTop == right.leftTop
|
||||||
|
&& left.size == right.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator !=(Rect<T> &left, Rect<T> &right)
|
||||||
|
{
|
||||||
|
return (left.leftTop != right.leftTop
|
||||||
|
&& left.size != right.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Rect<unsigned int> UIntRect;
|
||||||
|
typedef Rect<int> IntRect;
|
||||||
|
typedef Rect<float> FloatRect;
|
||||||
|
}
|
||||||
54
app/includes/CTRPluginFramework/System/Lock.hpp
Normal file
54
app/includes/CTRPluginFramework/System/Lock.hpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef CTRPLUGINFRAMEWORK_SYSTEM_LOCK_HPP
|
||||||
|
#define CTRPLUGINFRAMEWORK_SYSTEM_LOCK_HPP
|
||||||
|
|
||||||
|
#include "3ds.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Mutex;
|
||||||
|
class Lock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline explicit Lock(LightLock &llock) :
|
||||||
|
_type{LIGHTLOCK}, _llock{&llock}
|
||||||
|
{
|
||||||
|
LightLock_Lock(_llock);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit Lock(RecursiveLock &rlock) :
|
||||||
|
_type{RECLOCK}, _rlock{&rlock}
|
||||||
|
{
|
||||||
|
RecursiveLock_Lock(_rlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit Lock(Mutex &mutex) :
|
||||||
|
_type{MUTEX}, _mutex{&mutex}
|
||||||
|
{
|
||||||
|
mutex.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~Lock(void)
|
||||||
|
{
|
||||||
|
if (_type == LIGHTLOCK)
|
||||||
|
LightLock_Unlock(_llock);
|
||||||
|
else if (_type == RECLOCK)
|
||||||
|
RecursiveLock_Unlock(_rlock);
|
||||||
|
else if (_type == MUTEX)
|
||||||
|
_mutex->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const constexpr u32 LIGHTLOCK = 1;
|
||||||
|
static const constexpr u32 RECLOCK = 2;
|
||||||
|
static const constexpr u32 MUTEX = 3;
|
||||||
|
const u32 _type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
LightLock *_llock;
|
||||||
|
RecursiveLock *_rlock;
|
||||||
|
Mutex *_mutex;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
41
app/includes/CTRPluginFramework/System/Mutex.hpp
Normal file
41
app/includes/CTRPluginFramework/System/Mutex.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef CTRPLUGINFRAMEWORK_SYSTEM_MUTEX_HPP
|
||||||
|
#define CTRPLUGINFRAMEWORK_SYSTEM_MUTEX_HPP
|
||||||
|
|
||||||
|
#include "3ds.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Mutex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline Mutex(void) {
|
||||||
|
RecursiveLock_Init(&_lock);
|
||||||
|
}
|
||||||
|
inline ~Mutex(void) {
|
||||||
|
// I suppose that we can "force" unlock the mutex
|
||||||
|
if (_lock.counter > 0)
|
||||||
|
{
|
||||||
|
_lock.counter = 1;
|
||||||
|
RecursiveLock_Unlock(&_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Lock(void) {
|
||||||
|
RecursiveLock_Lock(&_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true on failure
|
||||||
|
inline bool TryLock(void) {
|
||||||
|
return RecursiveLock_TryLock(&_lock) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unlock(void) {
|
||||||
|
RecursiveLock_Unlock(&_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RecursiveLock _lock;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
205
app/includes/CTRPluginFramework/Time.hpp
Normal file
205
app/includes/CTRPluginFramework/Time.hpp
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "3ds/types.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Time
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
constexpr Time(void) : _ticks(0) {}
|
||||||
|
|
||||||
|
|
||||||
|
float AsSeconds(void) const;
|
||||||
|
|
||||||
|
int AsMilliseconds(void) const;
|
||||||
|
|
||||||
|
s64 AsMicroseconds(void) const;
|
||||||
|
|
||||||
|
inline s64 AsTicks(void) const { return _ticks; }
|
||||||
|
|
||||||
|
static const Time Zero; ///< Predefined "zero" time value
|
||||||
|
|
||||||
|
static constexpr u32 TicksPerSecond = 268111856U;
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
friend constexpr Time Seconds(float amount);
|
||||||
|
friend constexpr Time Milliseconds(int amount);
|
||||||
|
friend constexpr Time Microseconds(s64 amount);
|
||||||
|
friend constexpr Time Ticks(s64 amount);
|
||||||
|
|
||||||
|
constexpr Time(s64 ticks) : _ticks(ticks) {}
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
|
||||||
|
s64 _ticks;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Time Seconds(float amount)
|
||||||
|
{
|
||||||
|
return (Time(static_cast<s64>(amount * Time::TicksPerSecond)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constexpr Time Milliseconds(int amount)
|
||||||
|
{
|
||||||
|
return (Time(static_cast<s64>(amount * (Time::TicksPerSecond / 1000.f))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constexpr Time Microseconds(s64 amount)
|
||||||
|
{
|
||||||
|
return (Time(static_cast<s64>(amount * (Time::TicksPerSecond / 1000000.f))));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Time Ticks(s64 amount)
|
||||||
|
{
|
||||||
|
return (Time(amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator ==(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() == right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator !=(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() != right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator <(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() < right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator >(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() > right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator <=(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() <= right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator >=(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() >= right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Time operator -(const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(-right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator +(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(left.AsTicks() + right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator +=(Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left = left + right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator -(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(left.AsTicks() - right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator -=(Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return left = left - right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(const Time& left, float right)
|
||||||
|
{
|
||||||
|
return (Seconds(left.AsSeconds() * right));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(const Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (Microseconds(left.AsMicroseconds() * right));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(float left, const Time& right)
|
||||||
|
{
|
||||||
|
return (right * left);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(s64 left, const Time& right)
|
||||||
|
{
|
||||||
|
return (right * left);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator *=(Time& left, float right)
|
||||||
|
{
|
||||||
|
return (left = left * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator *=(Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (left = left * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator /(const Time& left, float right)
|
||||||
|
{
|
||||||
|
return Seconds(left.AsSeconds() / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator /(const Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (Microseconds(left.AsMicroseconds() / right));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator /=(Time& left, float right)
|
||||||
|
{
|
||||||
|
return (left = left / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator /=(Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (left = left / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline float operator /(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsSeconds() / right.AsSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator %(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(left.AsTicks() % right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator %=(Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left = left % right);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
124
app/includes/CTRPluginFramework/Vector.hpp
Normal file
124
app/includes/CTRPluginFramework/Vector.hpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds/types.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class Vector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vector();
|
||||||
|
Vector(T x, T y);
|
||||||
|
template <typename U>
|
||||||
|
explicit Vector(const Vector<U> &vector);
|
||||||
|
|
||||||
|
T x;
|
||||||
|
T y;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T>::Vector() : x(0), y(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T>::Vector(T x, T y) : x(x), y(y)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename U>
|
||||||
|
Vector<T>::Vector(const Vector<U> &vector) : x(static_cast<T>(vector.x)), y(static_cast<T>(vector.y))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator - (const Vector<T> &vector)
|
||||||
|
{
|
||||||
|
return (Vector<T>(-vector.x, -vector.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator - (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x - right.x, left.y - right.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator -= (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
left.x -= right.x;
|
||||||
|
left.y -= right.y;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator + (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x + right.x, left.y + right.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator += (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
left.x += right.x;
|
||||||
|
left.y += right.y;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator * (const Vector<T> &left, T right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x * right, left.y * right));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator * (const T left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(right.x * left, right.y * left));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator *= (Vector<T> &left, const T right)
|
||||||
|
{
|
||||||
|
left.x *= right;
|
||||||
|
left.y *= right;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator / (const Vector<T> &left, const T right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x / right, left.y / right));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator /= (Vector<T> &left, const T right)
|
||||||
|
{
|
||||||
|
left.x /= right;
|
||||||
|
left.y /= right;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator <= (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (left.x <= right.x
|
||||||
|
&& left.y <= right.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator >= (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (left.x >= right.x
|
||||||
|
&& left.y >= right.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Vector<unsigned int> UIntVector;
|
||||||
|
typedef Vector<int> IntVector;
|
||||||
|
typedef Vector<float> FloatVector;
|
||||||
|
typedef Vector<signed short> shortVector;
|
||||||
|
}
|
||||||
6
app/includes/Intellisense.hpp
Normal file
6
app/includes/Intellisense.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Only used by Visual Studio Intellisense
|
||||||
|
|
||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 0
|
||||||
|
#define VERSION_REVISION 1
|
||||||
|
#define SERVER_PORT 5543
|
||||||
47
app/includes/Logger.hpp
Normal file
47
app/includes/Logger.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds.h"
|
||||||
|
#include "string"
|
||||||
|
#include "queue"
|
||||||
|
#include "CTRPluginFramework/System/Mutex.hpp"
|
||||||
|
#include "CTRPluginFramework/System/Lock.hpp"
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
public:
|
||||||
|
Logger();
|
||||||
|
void Start();
|
||||||
|
void End();
|
||||||
|
~Logger();
|
||||||
|
void Raw(bool isTopScr, const char* fmt, ...);
|
||||||
|
void Info(const char* fmt, ...);
|
||||||
|
void Debug(const char* fmt, ...);
|
||||||
|
void Warning(const char* fmt, ...);
|
||||||
|
void Error(const char* fmt, ...);
|
||||||
|
void Traffic(const char* fmt, ...);
|
||||||
|
|
||||||
|
void Wait();
|
||||||
|
|
||||||
|
bool debug_enable = false;
|
||||||
|
private:
|
||||||
|
struct PendingLog {
|
||||||
|
enum class Type : u8 {
|
||||||
|
RAW,
|
||||||
|
DEBUG,
|
||||||
|
INFO,
|
||||||
|
WARNING,
|
||||||
|
ERROR,
|
||||||
|
TRAFFIC,
|
||||||
|
};
|
||||||
|
Type type;
|
||||||
|
bool isTopScr = true;
|
||||||
|
std::string string;
|
||||||
|
};
|
||||||
|
static void LoggerThread(void* arg);
|
||||||
|
void Handler();
|
||||||
|
Thread thread;
|
||||||
|
LightEvent event;
|
||||||
|
|
||||||
|
std::queue<PendingLog> pendingLogs;
|
||||||
|
CTRPluginFramework::Mutex pendingLogsMutex;
|
||||||
|
|
||||||
|
bool run = true;
|
||||||
|
};
|
||||||
5
app/includes/Main.hpp
Normal file
5
app/includes/Main.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds.h"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
extern Logger logger;
|
||||||
154
app/includes/csvc.h
Normal file
154
app/includes/csvc.h
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
/* This paricular file is licensed under the following terms: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
|
||||||
|
* for any damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
|
||||||
|
* and redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
||||||
|
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||||
|
* This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
/// Operations for svcControlService
|
||||||
|
typedef enum ServiceOp
|
||||||
|
{
|
||||||
|
SERVICEOP_STEAL_CLIENT_SESSION = 0, ///< Steal a client session given a service or global port name
|
||||||
|
SERVICEOP_GET_NAME, ///< Get the name of a service or global port given a client or session handle
|
||||||
|
} ServiceOp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Executes a function in supervisor mode, using the supervisor-mode stack.
|
||||||
|
* @param func Function to execute.
|
||||||
|
* @param ... Function parameters, up to 3 registers.
|
||||||
|
*/
|
||||||
|
Result svcCustomBackdoor(void *func, ...);
|
||||||
|
|
||||||
|
///@name I/O
|
||||||
|
///@{
|
||||||
|
/**
|
||||||
|
* @brief Gives the physical address corresponding to a virtual address.
|
||||||
|
* @param VA Virtual address.
|
||||||
|
* @param writeCheck whether to check if the VA is writable in supervisor mode
|
||||||
|
* @return The corresponding physical address, or NULL.
|
||||||
|
*/
|
||||||
|
u32 svcConvertVAToPA(const void *VA, bool writeCheck);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flushes a range of the data cache (L2C included).
|
||||||
|
* @param addr Start address.
|
||||||
|
* @param len Length of the range.
|
||||||
|
*/
|
||||||
|
void svcFlushDataCacheRange(void *addr, u32 len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flushes the data cache entirely (L2C included).
|
||||||
|
*/
|
||||||
|
void svcFlushEntireDataCache(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Invalidates a range of the instruction cache.
|
||||||
|
* @param addr Start address.
|
||||||
|
* @param len Length of the range.
|
||||||
|
*/
|
||||||
|
void svcInvalidateInstructionCacheRange(void *addr, u32 len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Invalidates the data cache entirely.
|
||||||
|
*/
|
||||||
|
void svcInvalidateEntireInstructionCache(void);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
///@name Memory management
|
||||||
|
///@{
|
||||||
|
/**
|
||||||
|
* @brief Maps a block of process memory.
|
||||||
|
* @param dstProcessHandle Handle of the process to map the memory in (destination)
|
||||||
|
* @param destAddress Address of the mapped block in the current process.
|
||||||
|
* @param srcProcessHandle Handle of the process to map the memory from (source)
|
||||||
|
* @param srcAddress Address of the mapped block in the source process.
|
||||||
|
* @param size Size of the block of the memory to map (truncated to a multiple of 0x1000 bytes).
|
||||||
|
*/
|
||||||
|
Result svcMapProcessMemoryEx(Handle dstProcessHandle, u32 destAddress, Handle srcProcessHandle, u32 vaSrc, u32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unmaps a block of process memory.
|
||||||
|
* @param process Handle of the process to unmap the memory from
|
||||||
|
* @param destAddress Address of the block of memory to unmap
|
||||||
|
* @param size Size of the block of memory to unmap (truncated to a multiple of 0x1000 bytes).
|
||||||
|
* This function should only be used to unmap memory mapped with svcMapProcessMemoryEx
|
||||||
|
*/
|
||||||
|
Result svcUnmapProcessMemoryEx(Handle process, u32 destAddress, u32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Controls memory mapping, with the choice to use region attributes or not.
|
||||||
|
* @param[out] addr_out The virtual address resulting from the operation. Usually the same as addr0.
|
||||||
|
* @param addr0 The virtual address to be used for the operation.
|
||||||
|
* @param addr1 The virtual address to be (un)mirrored by @p addr0 when using @ref MEMOP_MAP or @ref MEMOP_UNMAP.
|
||||||
|
* It has to be pointing to a RW memory.
|
||||||
|
* Use NULL if the operation is @ref MEMOP_FREE or @ref MEMOP_ALLOC.
|
||||||
|
* @param size The requested size for @ref MEMOP_ALLOC and @ref MEMOP_ALLOC_LINEAR.
|
||||||
|
* @param op Operation flags. See @ref MemOp.
|
||||||
|
* @param perm A combination of @ref MEMPERM_READ and @ref MEMPERM_WRITE. Using MEMPERM_EXECUTE will return an error.
|
||||||
|
* Value 0 is used when unmapping memory.
|
||||||
|
* @param isLoader Whether to use the region attributes
|
||||||
|
* If a memory is mapped for two or more addresses, you have to use MEMOP_UNMAP before being able to MEMOP_FREE it.
|
||||||
|
* MEMOP_MAP will fail if @p addr1 was already mapped to another address.
|
||||||
|
*
|
||||||
|
* @sa svcControlMemory
|
||||||
|
*/
|
||||||
|
Result svcControlMemoryEx(u32* addr_out, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
///@name System
|
||||||
|
///@{
|
||||||
|
/**
|
||||||
|
* @brief Performs actions related to services or global handles.
|
||||||
|
* @param op The operation to perform, see @ref ServiceOp.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* svcControlService(SERVICEOP_GET_NAME, (char [12])outName, (Handle)clientOrSessionHandle);
|
||||||
|
* svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, (Handle *)&outHandle, (const char *)name);
|
||||||
|
*/
|
||||||
|
Result svcControlService(ServiceOp op, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy a handle from a process to another one.
|
||||||
|
* @param[out] out The output handle.
|
||||||
|
* @param outProcess Handle of the process of the output handle.
|
||||||
|
* @param in The input handle. Pseudo-handles are not accepted.
|
||||||
|
* @param inProcess Handle of the process of the input handle.
|
||||||
|
*/
|
||||||
|
Result svcCopyHandle(Handle *out, Handle outProcess, Handle in, Handle inProcess);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the address and class name of the underlying kernel object corresponding to a handle.
|
||||||
|
* @param[out] outKAddr The output kernel address.
|
||||||
|
* @param[out] outName Output class name. The buffer should be large enough to contain it.
|
||||||
|
* @param in The input handle.
|
||||||
|
*/
|
||||||
|
Result svcTranslateHandle(u32 *outKAddr, char *outClassName, Handle in);
|
||||||
|
|
||||||
|
/// Operations for svcControlProcess
|
||||||
|
typedef enum ProcessOp
|
||||||
|
{
|
||||||
|
PROCESSOP_GET_ALL_HANDLES, ///< List all handles of the process, varg3 can be either 0 to fetch all handles, or token of the type to fetch
|
||||||
|
///< svcControlProcess(handle, PROCESSOP_GET_ALL_HANDLES, (u32)&outBuf, 0)
|
||||||
|
PROCESSOP_SET_MMU_TO_RWX, ///< Set the whole memory of the process with rwx access
|
||||||
|
///< svcControlProcess(handle, PROCESSOP_SET_MMU_TO_RWX, 0, 0)
|
||||||
|
PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT,
|
||||||
|
PROCESSOP_GET_ON_EXIT_EVENT,
|
||||||
|
PROCESSOP_GET_PA_FROM_VA, ///< Get the physical address of the va within the process
|
||||||
|
///< svcControlProcess(handle, PROCESSOP_GET_PA_FROM_VA, (u32)&outPa, va)
|
||||||
|
} ProcessOp;
|
||||||
|
|
||||||
|
Result svcControlProcess(Handle process, ProcessOp op, u32 varg2, u32 varg3);
|
||||||
|
///@}
|
||||||
9
app/includes/logo.h
Normal file
9
app/includes/logo.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* Generated by bin2c, do not edit manually */
|
||||||
|
#ifndef ____includes_logo_h_included
|
||||||
|
#define ____includes_logo_h_included
|
||||||
|
|
||||||
|
/* Contents of file .\data\logo.bin */
|
||||||
|
extern const long int __data_logo_bin_size;
|
||||||
|
extern const unsigned char __data_logo_bin[32808];
|
||||||
|
|
||||||
|
#endif /* ____includes_logo_h_included */
|
||||||
36
app/includes/plgldr.h
Normal file
36
app/includes/plgldr.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool noFlash;
|
||||||
|
u8 pluginMemoryStrategy;
|
||||||
|
u8 persistent;
|
||||||
|
u32 lowTitleId;
|
||||||
|
char path[256];
|
||||||
|
u32 config[32];
|
||||||
|
} PluginLoadParameters;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PLG_STRATEGY_NONE = 2,
|
||||||
|
PLG_STRATEGY_SWAP = 0,
|
||||||
|
PLG_STRATEGY_MODE3 = 1
|
||||||
|
} PluginMemoryStrategy;
|
||||||
|
|
||||||
|
Result plgLdrInit(void);
|
||||||
|
void plgLdrExit(void);
|
||||||
|
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled);
|
||||||
|
Result PLGLDR__SetPluginLoaderState(bool enabled);
|
||||||
|
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters);
|
||||||
|
Result PLGLDR__GetVersion(u32* version);
|
||||||
|
Result PLGLDR__SetExeDecSettings(void* decFunc, void* args);
|
||||||
|
Result PLGLDR__ClearPluginLoadParameters();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
BIN
app/resources/audio.cwav
Normal file
BIN
app/resources/audio.cwav
Normal file
Binary file not shown.
BIN
app/resources/banner.png
Normal file
BIN
app/resources/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
app/resources/icon.pdn
Normal file
BIN
app/resources/icon.pdn
Normal file
Binary file not shown.
BIN
app/resources/icon.png
Normal file
BIN
app/resources/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
BIN
app/resources/logo.bcma.lz
Normal file
BIN
app/resources/logo.bcma.lz
Normal file
Binary file not shown.
150
app/sources/BCLIM.cpp
Normal file
150
app/sources/BCLIM.cpp
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#include "BCLIM.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework {
|
||||||
|
|
||||||
|
static inline int ColorClamp(int Color)
|
||||||
|
{
|
||||||
|
if (Color > 255) Color = 255;
|
||||||
|
if (Color < 0) Color = 0;
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8 BCLIM::textureTileOrder[] =
|
||||||
|
{
|
||||||
|
0, 1, 4, 5,
|
||||||
|
2, 3, 6, 7,
|
||||||
|
|
||||||
|
8, 9, 12, 13,
|
||||||
|
10, 11, 14, 15
|
||||||
|
};
|
||||||
|
|
||||||
|
const u8 BCLIM::etc1Modifiers[][2] =
|
||||||
|
{
|
||||||
|
{ 2, 8 },
|
||||||
|
{ 5, 17 },
|
||||||
|
{ 9, 29 },
|
||||||
|
{ 13, 42 },
|
||||||
|
{ 18, 60 },
|
||||||
|
{ 24, 80 },
|
||||||
|
{ 33, 106 },
|
||||||
|
{ 47, 183 }
|
||||||
|
};
|
||||||
|
|
||||||
|
Color BCLIM::OpaqueBlendFunc(const Color& dst, const Color& src) {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color ReadPixel(void* fb, int posX, int posY) {
|
||||||
|
constexpr u32 _bytesPerPixel = 2;
|
||||||
|
constexpr u32 _rowSize = 240;
|
||||||
|
u32 offset = (_rowSize - 1 - posY + posX * _rowSize) * _bytesPerPixel;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u16 u;
|
||||||
|
u8 b[2];
|
||||||
|
} half;
|
||||||
|
half.u = *reinterpret_cast<u16 *>((u32)fb + offset);
|
||||||
|
Color c;
|
||||||
|
c.r = (half.u >> 8) & 0xF8;
|
||||||
|
c.g = (half.u >> 3) & 0xFC;
|
||||||
|
c.b = (half.u << 3) & 0xF8;
|
||||||
|
c.a = 255;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
static void WritePixel(void* fb, int posX, int posY, const Color& c) {
|
||||||
|
constexpr u32 _bytesPerPixel = 2;
|
||||||
|
constexpr u32 _rowSize = 240;
|
||||||
|
u32 offset = (_rowSize - 1 - posY + posX * _rowSize) * _bytesPerPixel;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u16 u;
|
||||||
|
u8 b[2];
|
||||||
|
} half;
|
||||||
|
half.u = (c.r & 0xF8) << 8;
|
||||||
|
half.u |= (c.g & 0xFC) << 3;
|
||||||
|
half.u |= (c.b & 0xF8) >> 3;
|
||||||
|
*reinterpret_cast<u16 *>((u32)fb + offset) = half.u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BCLIM::RenderInterfaceBackend(void* usrData, bool isRead, Color* c, int posX, int posY) {
|
||||||
|
if (isRead) {
|
||||||
|
*c = ReadPixel(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), posX, posY);
|
||||||
|
} else {
|
||||||
|
WritePixel(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), posX, posY, *c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FastContains(const Rect<int>& rect, Vector<int> point) {
|
||||||
|
return point.x >= rect.leftTop.x && point.x < (rect.leftTop.x + rect.size.x) &&
|
||||||
|
point.y >= rect.leftTop.y && point.y < (rect.leftTop.y + rect.size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BCLIM::Render(const Rect<int>& position, std::pair<void*, RenderBackend> backend, const Rect<int>& crop, const Rect<int>& limits, std::pair<bool, ColorBlendCallback> colorBlender) {
|
||||||
|
auto mappingScale = [](const Rect<int>& position, int x, int y, int w, int h) {
|
||||||
|
int posX = position.leftTop.x;
|
||||||
|
int posY = position.leftTop.y;
|
||||||
|
float progX = x/(float)w;
|
||||||
|
float progY = y/(float)h;
|
||||||
|
|
||||||
|
return Vector<int>(posX + position.size.x * progX, posY + position.size.y * progY);
|
||||||
|
};
|
||||||
|
auto mappingDirect = [](const Rect<int>& position, int x, int y, int w, int h) {
|
||||||
|
return Vector<int>(position.leftTop.x + x, position.leftTop.y + y);
|
||||||
|
};
|
||||||
|
Vector<int>(*mapping)(const Rect<int>& position, int x, int y, int w, int h);
|
||||||
|
Color current;
|
||||||
|
|
||||||
|
if (position.size.x == header->imag.width && position.size.y == header->imag.height)
|
||||||
|
mapping = mappingDirect;
|
||||||
|
else
|
||||||
|
mapping = mappingScale;
|
||||||
|
|
||||||
|
switch (header->imag.format) {
|
||||||
|
case TextureFormat::L8:
|
||||||
|
case TextureFormat::A8:
|
||||||
|
case TextureFormat::LA4:
|
||||||
|
case TextureFormat::LA8:
|
||||||
|
case TextureFormat::HILO8:
|
||||||
|
case TextureFormat::RGB8:
|
||||||
|
case TextureFormat::RGBA5551:
|
||||||
|
case TextureFormat::RGBA8:
|
||||||
|
case TextureFormat::ETC1:
|
||||||
|
case TextureFormat::L4:
|
||||||
|
case TextureFormat::A4:
|
||||||
|
case TextureFormat::RGBA4:
|
||||||
|
case TextureFormat::ETC1A4:
|
||||||
|
break;
|
||||||
|
case TextureFormat::RGB565:
|
||||||
|
{
|
||||||
|
int offs = 0;
|
||||||
|
Vector<int> prevPos(-1, -1);
|
||||||
|
for (int y = 0; y < header->imag.height; y+=8) {
|
||||||
|
for (int x = 0; x < header->imag.width; x+=8) {
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
int x2 = i % 8;
|
||||||
|
if (x + x2 >= crop.size.x || x + x2 >= header->imag.width) continue;
|
||||||
|
int y2 = i / 8;
|
||||||
|
if (y + y2 >= crop.size.y || y + y2 >= header->imag.height) continue;
|
||||||
|
auto drawPos = mapping(position, x + x2, y + y2, header->imag.width, header->imag.height);
|
||||||
|
if (!FastContains(limits, drawPos)) continue;
|
||||||
|
if (drawPos.x != prevPos.x || drawPos.y != prevPos.y) {
|
||||||
|
prevPos = drawPos;
|
||||||
|
int pos = textureTileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4);
|
||||||
|
u16 pixel = GetDataAt<u16>(offs + pos * 2);
|
||||||
|
u8 b = (u8)((pixel & 0x1F) << 3);
|
||||||
|
u8 g = (u8)((pixel & 0x7E0) >> 3);
|
||||||
|
u8 r = (u8)((pixel & 0xF800) >> 8);
|
||||||
|
if (colorBlender.first)
|
||||||
|
backend.second(backend.first, true, ¤t, drawPos.x, drawPos.y);
|
||||||
|
Color finalcolor = colorBlender.second(Color(r, g, b), current);
|
||||||
|
backend.second(backend.first, false, &finalcolor, drawPos.x, drawPos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offs += 64 * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
158
app/sources/CTRPluginFramework/Color.cpp
Normal file
158
app/sources/CTRPluginFramework/Color.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#include "CTRPluginFramework/Color.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
Color& Color::Fade(float fading)
|
||||||
|
{
|
||||||
|
if (fading > 1.0f || fading < -1.0f)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
if (fading > 0.0f)
|
||||||
|
{
|
||||||
|
float tint = 1.f - fading;
|
||||||
|
r = std::min((int)(255 - (255 - r) * tint), 255);
|
||||||
|
g = std::min((int)(255 - (255 - g) * tint), 255);
|
||||||
|
b = std::min((int)(255 - (255 - b) * tint), 255);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float shade = 1.f + fading;
|
||||||
|
|
||||||
|
r *= shade;
|
||||||
|
g *= shade;
|
||||||
|
b *= shade;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::Blend(const Color &color, BlendMode mode) const
|
||||||
|
{
|
||||||
|
// This is background, color is foreground
|
||||||
|
Color ret;
|
||||||
|
unsigned int _r;
|
||||||
|
unsigned int _g;
|
||||||
|
unsigned int _b;
|
||||||
|
unsigned int _a;
|
||||||
|
float forealpha = (float)color.a / 255.f;
|
||||||
|
float minusForeAlpha = 1.f - forealpha;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case BlendMode::Alpha:
|
||||||
|
_r = (forealpha * (float)color.r) + ((float)r * minusForeAlpha);
|
||||||
|
_g = (forealpha * (float)color.g) + ((float)g * minusForeAlpha);
|
||||||
|
_b = (forealpha * (float)color.b) + ((float)b * minusForeAlpha);
|
||||||
|
_a = color.a * a;
|
||||||
|
ret.r = std::min(_r, 255u);
|
||||||
|
ret.g = std::min(_g, 255u);
|
||||||
|
ret.b = std::min(_b, 255u);
|
||||||
|
ret.a = std::min(_a, 255u);
|
||||||
|
break;
|
||||||
|
case BlendMode::Add:
|
||||||
|
_r = a * r / 255 + 255 * color.r / 255;
|
||||||
|
_g = a * g / 255 + 255 * color.g / 255;
|
||||||
|
_b = a * b / 255 + 255 * color.b / 255;
|
||||||
|
_a = a + color.a;
|
||||||
|
ret.r = std::min(_r, 255u);
|
||||||
|
ret.g = std::min(_g, 255u);
|
||||||
|
ret.b = std::min(_b, 255u);
|
||||||
|
ret.a = std::min(_a, 255u);
|
||||||
|
break;
|
||||||
|
case BlendMode::Sub:
|
||||||
|
_r = a * r / 255 - 255 * color.r / 255;
|
||||||
|
_g = a * g / 255 - 255 * color.g / 255;
|
||||||
|
_b = a * b / 255 - 255 * color.b / 255;
|
||||||
|
_a = a - color.a;
|
||||||
|
ret.r = std::max(_r, 0u);
|
||||||
|
ret.g = std::max(_g, 0u);
|
||||||
|
ret.b = std::max(_b, 0u);
|
||||||
|
ret.a = std::max(_a, 0u);
|
||||||
|
break;
|
||||||
|
case BlendMode::Mul:
|
||||||
|
ret = *this * color;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = color;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator < (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r < right.r)
|
||||||
|
&& (b < right.b)
|
||||||
|
&& (g < right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator <= (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r <= right.r)
|
||||||
|
&& (b <= right.b)
|
||||||
|
&& (g <= right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator > (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r > right.r)
|
||||||
|
&& (b > right.b)
|
||||||
|
&& (g > right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator >= (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r >= right.r)
|
||||||
|
&& (b >= right.b)
|
||||||
|
&& (g >= right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::operator+(const Color& right) const
|
||||||
|
{
|
||||||
|
u8 _r(std::min(r + right.r, 255));
|
||||||
|
u8 _g(std::min(g + right.g, 255));
|
||||||
|
u8 _b(std::min(b + right.b, 255));
|
||||||
|
u8 _a(std::min(a + right.a, 255));
|
||||||
|
|
||||||
|
return (Color(_r, _g, _b, _a));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::operator-(const Color& right) const
|
||||||
|
{
|
||||||
|
u8 _r(std::max(r - right.r, 0));
|
||||||
|
u8 _g(std::max(g - right.g, 0));
|
||||||
|
u8 _b(std::max(b - right.b, 0));
|
||||||
|
u8 _a(std::max(a - right.a, 0));
|
||||||
|
|
||||||
|
return (Color(_r, _g, _b, _a));
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::operator*(const Color& right) const
|
||||||
|
{
|
||||||
|
u8 _r(r * right.r / 255);
|
||||||
|
u8 _g(g * right.g / 255);
|
||||||
|
u8 _b(b * right.b / 255);
|
||||||
|
u8 _a(a * right.a / 255);
|
||||||
|
|
||||||
|
return (Color(_r, _g, _b, _a));
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &Color::operator+=(const Color& right)
|
||||||
|
{
|
||||||
|
*this = *this + right;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &Color::operator-=(const Color& right)
|
||||||
|
{
|
||||||
|
*this = *this - right;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &Color::operator*=(const Color& right)
|
||||||
|
{
|
||||||
|
*this = *this * right;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/sources/CTRPluginFramework/Time.cpp
Normal file
26
app/sources/CTRPluginFramework/Time.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "3ds/types.h"
|
||||||
|
|
||||||
|
#include "CTRPluginFramework/Time.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
const Time Time::Zero;
|
||||||
|
|
||||||
|
float Time::AsSeconds(void) const
|
||||||
|
{
|
||||||
|
return (_ticks / (float)TicksPerSecond);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Time::AsMilliseconds(void) const
|
||||||
|
{
|
||||||
|
return static_cast<int>(_ticks / (TicksPerSecond / 1000.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s64 Time::AsMicroseconds(void) const
|
||||||
|
{
|
||||||
|
return static_cast<s64>(_ticks / (TicksPerSecond / 1000000.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
178
app/sources/Logger.cpp
Normal file
178
app/sources/Logger.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#include "Logger.hpp"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "3ds.h"
|
||||||
|
|
||||||
|
Logger::Logger() {}
|
||||||
|
|
||||||
|
void Logger::Start() {
|
||||||
|
LightEvent_Init(&event, ResetType::RESET_ONESHOT);
|
||||||
|
|
||||||
|
s32 prio = 0;
|
||||||
|
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
|
||||||
|
|
||||||
|
thread = threadCreate(LoggerThread, this, 0x300, prio + 1, -2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::End() {
|
||||||
|
run = false;
|
||||||
|
LightEvent_Signal(&event);
|
||||||
|
threadJoin(thread, U64_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::~Logger() {
|
||||||
|
if (run) End();
|
||||||
|
threadFree(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern PrintConsole topScreenConsole, bottomScreenConsole;
|
||||||
|
|
||||||
|
void Logger::Raw(bool isTopScr, const char* fmt, ...) {
|
||||||
|
va_list valist;
|
||||||
|
char buffer[256];
|
||||||
|
va_start(valist, fmt);
|
||||||
|
int ret = vsnprintf(buffer, 255, fmt, valist);
|
||||||
|
va_end(valist);
|
||||||
|
if (ret >= 0) buffer[ret] = '\0';
|
||||||
|
{
|
||||||
|
CTRPluginFramework::Lock l(pendingLogsMutex);
|
||||||
|
pendingLogs.push(PendingLog{.type = PendingLog::Type::RAW, .isTopScr = isTopScr, .string{buffer}});
|
||||||
|
}
|
||||||
|
LightEvent_Signal(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Info(const char* fmt, ...) {
|
||||||
|
va_list valist;
|
||||||
|
char buffer[256];
|
||||||
|
va_start(valist, fmt);
|
||||||
|
int ret = vsnprintf(buffer, 255, fmt, valist);
|
||||||
|
va_end(valist);
|
||||||
|
if (ret >= 0) buffer[ret] = '\0';
|
||||||
|
{
|
||||||
|
CTRPluginFramework::Lock l(pendingLogsMutex);
|
||||||
|
pendingLogs.push(PendingLog{.type = PendingLog::Type::INFO, .isTopScr = true, .string{buffer}});
|
||||||
|
}
|
||||||
|
LightEvent_Signal(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Debug(const char* fmt, ...) {
|
||||||
|
if (!debug_enable) return;
|
||||||
|
va_list valist;
|
||||||
|
char buffer[256];
|
||||||
|
va_start(valist, fmt);
|
||||||
|
int ret = vsnprintf(buffer, 255, fmt, valist);
|
||||||
|
va_end(valist);
|
||||||
|
if (ret >= 0) buffer[ret] = '\0';
|
||||||
|
{
|
||||||
|
CTRPluginFramework::Lock l(pendingLogsMutex);
|
||||||
|
pendingLogs.push(PendingLog{.type = PendingLog::Type::DEBUG, .isTopScr = true, .string{buffer}});
|
||||||
|
}
|
||||||
|
LightEvent_Signal(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Warning(const char* fmt, ...) {
|
||||||
|
va_list valist;
|
||||||
|
char buffer[256];
|
||||||
|
va_start(valist, fmt);
|
||||||
|
int ret = vsnprintf(buffer, 255, fmt, valist);
|
||||||
|
va_end(valist);
|
||||||
|
if (ret >= 0) buffer[ret] = '\0';
|
||||||
|
{
|
||||||
|
CTRPluginFramework::Lock l(pendingLogsMutex);
|
||||||
|
pendingLogs.push(PendingLog{.type = PendingLog::Type::WARNING, .isTopScr = true, .string{buffer}});
|
||||||
|
}
|
||||||
|
LightEvent_Signal(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Error(const char* fmt, ...) {
|
||||||
|
va_list valist;
|
||||||
|
char buffer[256];
|
||||||
|
va_start(valist, fmt);
|
||||||
|
int ret = vsnprintf(buffer, 255, fmt, valist);
|
||||||
|
va_end(valist);
|
||||||
|
if (ret >= 0) buffer[ret] = '\0';
|
||||||
|
{
|
||||||
|
CTRPluginFramework::Lock l(pendingLogsMutex);
|
||||||
|
pendingLogs.push(PendingLog{.type = PendingLog::Type::ERROR, .isTopScr = true, .string{buffer}});
|
||||||
|
}
|
||||||
|
LightEvent_Signal(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Traffic(const char* fmt, ...) {
|
||||||
|
va_list valist;
|
||||||
|
char buffer[256];
|
||||||
|
va_start(valist, fmt);
|
||||||
|
int ret = vsnprintf(buffer, 255, fmt, valist);
|
||||||
|
va_end(valist);
|
||||||
|
if (ret >= 0) buffer[ret] = '\0';
|
||||||
|
{
|
||||||
|
CTRPluginFramework::Lock l(pendingLogsMutex);
|
||||||
|
pendingLogs.push(PendingLog{.type = PendingLog::Type::TRAFFIC, .isTopScr = false, .string{buffer}});
|
||||||
|
}
|
||||||
|
LightEvent_Signal(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Handler() {
|
||||||
|
bool currentIsTop = true;
|
||||||
|
int back;
|
||||||
|
while (true) {
|
||||||
|
LightEvent_Wait(&event);
|
||||||
|
if (!run) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (run) {
|
||||||
|
PendingLog log;
|
||||||
|
{
|
||||||
|
CTRPluginFramework::Lock l(pendingLogsMutex);
|
||||||
|
if (!pendingLogs.size())
|
||||||
|
break;
|
||||||
|
log = pendingLogs.front();
|
||||||
|
pendingLogs.pop();
|
||||||
|
}
|
||||||
|
if (log.isTopScr && !currentIsTop) {
|
||||||
|
currentIsTop = true;
|
||||||
|
consoleSelect(&topScreenConsole);
|
||||||
|
}
|
||||||
|
if (!log.isTopScr && currentIsTop) {
|
||||||
|
currentIsTop = false;
|
||||||
|
consoleSelect(&bottomScreenConsole);
|
||||||
|
}
|
||||||
|
switch (log.type)
|
||||||
|
{
|
||||||
|
case PendingLog::Type::RAW:
|
||||||
|
printf("%s\n", log.string.c_str());
|
||||||
|
break;
|
||||||
|
case PendingLog::Type::DEBUG:
|
||||||
|
printf("[D] %s\n", log.string.c_str());
|
||||||
|
break;
|
||||||
|
case PendingLog::Type::INFO:
|
||||||
|
printf("[I] %s\n", log.string.c_str());
|
||||||
|
break;
|
||||||
|
case PendingLog::Type::WARNING:
|
||||||
|
topScreenConsole.fg = 19;
|
||||||
|
printf("[W] %s\n", log.string.c_str());
|
||||||
|
topScreenConsole.fg = 0;
|
||||||
|
break;
|
||||||
|
case PendingLog::Type::ERROR:
|
||||||
|
topScreenConsole.fg = 17;
|
||||||
|
printf("[E] %s\n", log.string.c_str());
|
||||||
|
topScreenConsole.fg = 0;
|
||||||
|
break;
|
||||||
|
case PendingLog::Type::TRAFFIC:
|
||||||
|
back = bottomScreenConsole.cursorY;
|
||||||
|
bottomScreenConsole.cursorY = 25;
|
||||||
|
printf(log.string.c_str());
|
||||||
|
bottomScreenConsole.cursorY = back;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::LoggerThread(void* arg) {
|
||||||
|
Logger* l = (Logger*)arg;
|
||||||
|
l->Handler();
|
||||||
|
}
|
||||||
122
app/sources/csvc.s
Normal file
122
app/sources/csvc.s
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
@ This paricular file is licensed under the following terms:
|
||||||
|
|
||||||
|
@ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
|
||||||
|
@ for any damages arising from the use of this software.
|
||||||
|
@
|
||||||
|
@ Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
|
||||||
|
@ and redistribute it freely, subject to the following restrictions:
|
||||||
|
@
|
||||||
|
@ The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
||||||
|
@ If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||||
|
@
|
||||||
|
@ Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||||
|
@ This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
.arm
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
.macro SVC_BEGIN name
|
||||||
|
.section .text.\name, "ax", %progbits
|
||||||
|
.global \name
|
||||||
|
.type \name, %function
|
||||||
|
.align 2
|
||||||
|
.cfi_startproc
|
||||||
|
\name:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro SVC_END
|
||||||
|
.cfi_endproc
|
||||||
|
.endm
|
||||||
|
|
||||||
|
SVC_BEGIN svcCustomBackdoor
|
||||||
|
svc 0x80
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcConvertVAToPA
|
||||||
|
svc 0x90
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcFlushDataCacheRange
|
||||||
|
svc 0x91
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcFlushEntireDataCache
|
||||||
|
svc 0x92
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcInvalidateInstructionCacheRange
|
||||||
|
svc 0x93
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcInvalidateEntireInstructionCache
|
||||||
|
svc 0x94
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcMapProcessMemoryEx
|
||||||
|
str r4, [sp, #-4]!
|
||||||
|
ldr r4, [sp, #4]
|
||||||
|
svc 0xA0
|
||||||
|
ldr r4, [sp], #4
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcUnmapProcessMemoryEx
|
||||||
|
svc 0xA1
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlMemoryEx
|
||||||
|
push {r0, r4, r5}
|
||||||
|
ldr r0, [sp, #0xC]
|
||||||
|
ldr r4, [sp, #0xC+0x4]
|
||||||
|
ldr r5, [sp, #0xC+0x8]
|
||||||
|
svc 0xA2
|
||||||
|
pop {r2, r4, r5}
|
||||||
|
str r1, [r2]
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlMemoryUnsafe
|
||||||
|
str r4, [sp, #-4]!
|
||||||
|
ldr r4, [sp, #4]
|
||||||
|
svc 0xA3
|
||||||
|
ldr r4, [sp], #4
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcFreeMemory
|
||||||
|
svc 0xA3
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlService
|
||||||
|
svc 0xB0
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcCopyHandle
|
||||||
|
str r0, [sp, #-4]!
|
||||||
|
svc 0xB1
|
||||||
|
ldr r2, [sp], #4
|
||||||
|
str r1, [r2]
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcTranslateHandle
|
||||||
|
str r0, [sp, #-4]!
|
||||||
|
svc 0xB2
|
||||||
|
ldr r2, [sp], #4
|
||||||
|
str r1, [r2]
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlProcess
|
||||||
|
svc 0xB3
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
2057
app/sources/logo.c
Normal file
2057
app/sources/logo.c
Normal file
File diff suppressed because it is too large
Load Diff
236
app/sources/main.cpp
Normal file
236
app/sources/main.cpp
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "sys/stat.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
#include "Main.hpp"
|
||||||
|
#include "plgldr.h"
|
||||||
|
#include "BCLIM.hpp"
|
||||||
|
#include "logo.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "3gx.h"
|
||||||
|
|
||||||
|
Logger logger;
|
||||||
|
|
||||||
|
const char* artic_setup_plugin = "/3ds/AzaharArticSetup/AzaharArticSetup.3gx";
|
||||||
|
|
||||||
|
char *strdup(const char *s) {
|
||||||
|
char *d = (char*)malloc(strlen(s) + 1);
|
||||||
|
if (d == NULL) return NULL;
|
||||||
|
strcpy(d, s);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* fopen_mkdir(const char* name, const char* mode, bool actuallyOpen = true)
|
||||||
|
{
|
||||||
|
char* _path = strdup(name);
|
||||||
|
char *p;
|
||||||
|
FILE* retfile = NULL;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
for (p = _path + 1; *p; p++)
|
||||||
|
{
|
||||||
|
if (*p == '/')
|
||||||
|
{
|
||||||
|
*p = '\0';
|
||||||
|
if (mkdir(_path, 777) != 0)
|
||||||
|
if (errno != EEXIST) goto error;
|
||||||
|
*p = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (actuallyOpen) retfile = fopen(name, mode);
|
||||||
|
error:
|
||||||
|
free(_path);
|
||||||
|
return retfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool extractPlugin() {
|
||||||
|
u32 expectedVersion = SYSTEM_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||||
|
bool plugin_needs_update = true;
|
||||||
|
FILE* f = fopen(artic_setup_plugin, "r");
|
||||||
|
if (f) {
|
||||||
|
_3gx_Header header;
|
||||||
|
int read = fread(&header, 1, sizeof(header), f);
|
||||||
|
if (read == sizeof(header) && header.magic == _3GX_MAGIC) {
|
||||||
|
plugin_needs_update = header.version != expectedVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (f) fclose(f);
|
||||||
|
|
||||||
|
if (plugin_needs_update) {
|
||||||
|
logger.Info("Updating Azahar Artic Setup plugin file");
|
||||||
|
f = fopen_mkdir(artic_setup_plugin, "w");
|
||||||
|
if (!f) {
|
||||||
|
logger.Error("Cannot open plugin file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int written = fwrite(plugin_AzaharArticSetup_3gx, 1, plugin_AzaharArticSetup_3gx_size, f);
|
||||||
|
fclose(f);
|
||||||
|
if (written != plugin_AzaharArticSetup_3gx_size) {
|
||||||
|
logger.Error("Cannot write plugin file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool launchPlugin() {
|
||||||
|
u32 ret = 0;
|
||||||
|
PluginLoadParameters plgparam = { 0 };
|
||||||
|
u8 isPlgEnabled = 0;
|
||||||
|
|
||||||
|
plgparam.noFlash = true;
|
||||||
|
plgparam.pluginMemoryStrategy = PLG_STRATEGY_NONE;
|
||||||
|
plgparam.persistent = 0;
|
||||||
|
plgparam.lowTitleId = 0;
|
||||||
|
strcpy(plgparam.path, artic_setup_plugin);
|
||||||
|
|
||||||
|
ret = plgLdrInit();
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
logger.Error("Cannot start plugin loader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
u32 version;
|
||||||
|
ret = PLGLDR__GetVersion(&version);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
logger.Error("Plugin loader error");
|
||||||
|
plgLdrExit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (version < SYSTEM_VERSION(1,0,2)) {
|
||||||
|
logger.Error("Unsupported plugin loader version,");
|
||||||
|
logger.Error("please update Luma3DS");
|
||||||
|
plgLdrExit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ret = PLGLDR__IsPluginLoaderEnabled((bool*)&isPlgEnabled);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
logger.Error("Plugin loader error");
|
||||||
|
plgLdrExit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
plgparam.config[0] = isPlgEnabled;
|
||||||
|
ret = PLGLDR__SetPluginLoaderState(true);
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
logger.Error("Cannot enable plugin loader");
|
||||||
|
plgLdrExit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ret = PLGLDR__SetPluginLoadParameters(&plgparam);
|
||||||
|
plgLdrExit();
|
||||||
|
if (R_FAILED(ret)) {
|
||||||
|
logger.Error("Plugin loader error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintConsole topScreenConsole, bottomScreenConsole;
|
||||||
|
int transferedBytes = 0;
|
||||||
|
void Main() {
|
||||||
|
logger.Start();
|
||||||
|
logger.debug_enable = true;
|
||||||
|
|
||||||
|
gfxInitDefault();
|
||||||
|
consoleInit(GFX_TOP, &topScreenConsole);
|
||||||
|
consoleInit(GFX_BOTTOM, &bottomScreenConsole);
|
||||||
|
topScreenConsole.bg = 15; topScreenConsole.fg = 0;
|
||||||
|
bottomScreenConsole.bg = 15; bottomScreenConsole.fg = 0;
|
||||||
|
|
||||||
|
gfxSetDoubleBuffering(GFX_BOTTOM, false);
|
||||||
|
|
||||||
|
aptSetHomeAllowed(false);
|
||||||
|
|
||||||
|
consoleSelect(&bottomScreenConsole);
|
||||||
|
consoleClear();
|
||||||
|
consoleSelect(&topScreenConsole);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
{
|
||||||
|
CTRPluginFramework::BCLIM((void*)__data_logo_bin, __data_logo_bin_size).Render(CTRPluginFramework::Rect<int>((320 - 128) / 2, (240 - 128) / 2, 128, 128));
|
||||||
|
}
|
||||||
|
logger.Raw(false, "\n Azahar Artic Setup v%d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||||
|
logger.Raw(false, " Press A to launch setup tool.");
|
||||||
|
logger.Raw(false, " Press B or START to exit.");
|
||||||
|
logger.Raw(true, "");
|
||||||
|
logger.Info("Welcome to Azahar Artic Setup Tool!\n Only use this tool with Azahar Emulator\n\n Check bottom screen for controls.");
|
||||||
|
|
||||||
|
bool do_jump = false;
|
||||||
|
while (aptMainLoop())
|
||||||
|
{
|
||||||
|
//Scan all the inputs. This should be done once for each frame
|
||||||
|
hidScanInput();
|
||||||
|
|
||||||
|
//hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame)
|
||||||
|
u32 kDown = hidKeysDown();
|
||||||
|
|
||||||
|
if (kDown & (KEY_B | KEY_START)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kDown & KEY_A) {
|
||||||
|
logger.Info("Launching Azahar Artic Setup");
|
||||||
|
bool done = extractPlugin() && launchPlugin();
|
||||||
|
if (done) {
|
||||||
|
do_jump = true;
|
||||||
|
logger.Raw(true, "");
|
||||||
|
logger.Info("Done! Please wait...");
|
||||||
|
svcSleepThread(3000000000);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
logger.Error("Failed to launch Azahar Artic Setup");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush and swap framebuffers
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
|
||||||
|
//Wait for VBlank
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush and swap framebuffers
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
|
||||||
|
//Wait for VBlank
|
||||||
|
gspWaitForVBlank();
|
||||||
|
|
||||||
|
gfxExit();
|
||||||
|
gspLcdExit();
|
||||||
|
logger.End();
|
||||||
|
|
||||||
|
if (do_jump) {
|
||||||
|
OS_VersionBin cver = {0};
|
||||||
|
OS_VersionBin nver = {0};
|
||||||
|
osGetSystemVersionData(&nver, &cver);
|
||||||
|
u64 program_id = 0;
|
||||||
|
if (cver.region == 'E') {
|
||||||
|
program_id = 0x0004001000022000;
|
||||||
|
} else if (cver.region == 'U') {
|
||||||
|
program_id = 0x0004001000021000;
|
||||||
|
} else if (cver.region == 'J') {
|
||||||
|
program_id = 0x0004001000020000;
|
||||||
|
} else if (cver.region == 'C') {
|
||||||
|
program_id = 0x0004001000026000;
|
||||||
|
} else if (cver.region == 'K') {
|
||||||
|
program_id = 0x0004001000027000;
|
||||||
|
} else if (cver.region == 'T') {
|
||||||
|
program_id = 0x0004001000028000;
|
||||||
|
}
|
||||||
|
aptSetChainloader(program_id, MEDIATYPE_NAND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
int main(int argc, char* argv[]);
|
||||||
|
}
|
||||||
|
// Entrypoint, game will starts when you exit this function
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
Main();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
134
app/sources/plgldr.c
Normal file
134
app/sources/plgldr.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#include <3ds.h>
|
||||||
|
#include "plgldr.h"
|
||||||
|
#include "csvc.h"
|
||||||
|
|
||||||
|
static Handle plgLdrHandle = 0;
|
||||||
|
static int plgLdrRefCount;
|
||||||
|
|
||||||
|
Result plgLdrInit(void)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
if (AtomicPostIncrement(&plgLdrRefCount) == 0)
|
||||||
|
res = svcConnectToPort(&plgLdrHandle, "plg:ldr");
|
||||||
|
|
||||||
|
if (R_FAILED(res)) AtomicDecrement(&plgLdrRefCount);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plgLdrExit(void)
|
||||||
|
{
|
||||||
|
if (AtomicDecrement(&plgLdrRefCount))
|
||||||
|
return;
|
||||||
|
svcCloseHandle(plgLdrHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(2, 0, 0);
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
*isEnabled = cmdbuf[2];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__SetPluginLoaderState(bool enabled)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(3, 1, 0);
|
||||||
|
cmdbuf[1] = (u32)enabled;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(4, 2, 4);
|
||||||
|
cmdbuf[1] = (u32)parameters->noFlash | (((u32)parameters->pluginMemoryStrategy) << 8) | (((u32)parameters->persistent) << 16);
|
||||||
|
cmdbuf[2] = parameters->lowTitleId;
|
||||||
|
cmdbuf[3] = IPC_Desc_Buffer(256, IPC_BUFFER_R);
|
||||||
|
cmdbuf[4] = (u32)parameters->path;
|
||||||
|
cmdbuf[5] = IPC_Desc_Buffer(32 * sizeof(u32), IPC_BUFFER_R);
|
||||||
|
cmdbuf[6] = (u32)parameters->config;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__GetVersion(u32* version)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32* cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(8, 0, 0);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
if (cmdbuf[0] != IPC_MakeHeader(8, 2, 0))
|
||||||
|
return 0xD900182F;
|
||||||
|
|
||||||
|
res = cmdbuf[1];
|
||||||
|
if (version)
|
||||||
|
*version = cmdbuf[2];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__SetExeDecSettings(void* decFunc, void* args)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 buf[0x10] = { 0 };
|
||||||
|
u32* trueArgs;
|
||||||
|
if (args) trueArgs = args;
|
||||||
|
else trueArgs = buf;
|
||||||
|
|
||||||
|
u32* cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(13, 1, 2);
|
||||||
|
cmdbuf[1] = (decFunc) ? svcConvertVAToPA(decFunc, false) | (1 << 31) : 0;
|
||||||
|
cmdbuf[2] = IPC_Desc_Buffer(16 * sizeof(u32), IPC_BUFFER_R);
|
||||||
|
cmdbuf[3] = (u32)trueArgs;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__ClearPluginLoadParameters()
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(14, 0, 0);
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
BIN
images/logo_small.png
Normal file
BIN
images/logo_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
3
plugin/.gitignore
vendored
Normal file
3
plugin/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/build
|
||||||
|
*.3gx
|
||||||
|
.vscode/
|
||||||
202
plugin/3gx.ld
Normal file
202
plugin/3gx.ld
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||||
|
OUTPUT_ARCH(arm)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
code PT_LOAD FLAGS(5) /* Read | Execute */;
|
||||||
|
rodata PT_LOAD FLAGS(4) /* Read */;
|
||||||
|
data PT_LOAD FLAGS(6) /* Read | Write */;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* =========== CODE section =========== */
|
||||||
|
|
||||||
|
PROVIDE(__start__ = 0x07000100);
|
||||||
|
. = __start__;
|
||||||
|
|
||||||
|
.text ALIGN(4) :
|
||||||
|
{
|
||||||
|
/* .init */
|
||||||
|
KEEP( *(.crt0) )
|
||||||
|
KEEP( *(.init) )
|
||||||
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
/* .text */
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.glue_7t)
|
||||||
|
*(.stub)
|
||||||
|
*(.gnu.warning)
|
||||||
|
*(.gnu.linkonce.t*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
/* .fini */
|
||||||
|
KEEP( *(.fini) )
|
||||||
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
} : code
|
||||||
|
__text_end__ = .;
|
||||||
|
|
||||||
|
/* =========== RODATA section =========== */
|
||||||
|
|
||||||
|
.rodata ALIGN(0x4) :
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
*(.roda)
|
||||||
|
*(.rodata.*)
|
||||||
|
*all.rodata*(*)
|
||||||
|
*(.gnu.linkonce.r*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
. = ALIGN(4);
|
||||||
|
__tdata_align = .;
|
||||||
|
LONG (ALIGNOF(.tdata));
|
||||||
|
. = ALIGN(4);
|
||||||
|
} : rodata
|
||||||
|
|
||||||
|
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } : rodata
|
||||||
|
__exidx_start = .;
|
||||||
|
ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } : rodata
|
||||||
|
__exidx_end = .;
|
||||||
|
|
||||||
|
/* =========== DATA section =========== */
|
||||||
|
|
||||||
|
.data ALIGN(4):
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
*(.data.*)
|
||||||
|
*(.gnu.linkonce.d*)
|
||||||
|
CONSTRUCTORS
|
||||||
|
. = ALIGN(4);
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.tdata : ALIGN(4)
|
||||||
|
{
|
||||||
|
__tdata_lma = .;
|
||||||
|
*(.tdata)
|
||||||
|
*(.tdata.*)
|
||||||
|
*(.gnu.linkonce.td.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
__tdata_lma_end = .;
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.tbss : ALIGN(4)
|
||||||
|
{
|
||||||
|
*(.tbss)
|
||||||
|
*(.tbss.*)
|
||||||
|
*(.gnu.linkonce.tb.*)
|
||||||
|
*(.tcommon)
|
||||||
|
. = ALIGN(4);
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.preinit_array ALIGN(4) :
|
||||||
|
{
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.init_array ALIGN(4) :
|
||||||
|
{
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.fini_array ALIGN(4) :
|
||||||
|
{
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.ctors ALIGN(4) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.dtors ALIGN(4) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
} : data
|
||||||
|
|
||||||
|
__bss_start__ = .;
|
||||||
|
.bss ALIGN(4) :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss)
|
||||||
|
*(.bss.*)
|
||||||
|
*(.gnu.linkonce.b*)
|
||||||
|
*(COMMON)
|
||||||
|
|
||||||
|
/* Reserve space for the TLS segment of the main thread.
|
||||||
|
We need (__tls_start - 8) to be aligned the same as .tdata, to account for
|
||||||
|
the 8-byte ARM TLS header. Since the header is not actually used for
|
||||||
|
ARM_TLS_LE32 relocation, we just fake it by subtracting 8 from the data
|
||||||
|
offset.
|
||||||
|
*/
|
||||||
|
. = 8 + ABSOLUTE(ALIGN(ABSOLUTE(. - 8), ALIGNOF(.tdata)));
|
||||||
|
__tls_start = .;
|
||||||
|
. += SIZEOF(.tdata);
|
||||||
|
/* Ensure the alignment of .tbss is accounted for in the total size,
|
||||||
|
since SIZEOF(.tdata) doesn't include any padding before .tbss.
|
||||||
|
*/
|
||||||
|
. = ALIGN(ALIGNOF(.tbss));
|
||||||
|
. += SIZEOF(.tbss);
|
||||||
|
__tls_end = .;
|
||||||
|
} : data
|
||||||
|
__bss_end__ = .;
|
||||||
|
|
||||||
|
__end__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
|
/* ==================
|
||||||
|
==== Metadata ====
|
||||||
|
================== */
|
||||||
|
|
||||||
|
/* Discard sections that difficult post-processing */
|
||||||
|
/DISCARD/ : { *(.group .comment .note) }
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
}
|
||||||
1
plugin/ArticProtocol
Submodule
1
plugin/ArticProtocol
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 842ab851afb6e08419d1f0a94bf3450a2080a21e
|
||||||
27
plugin/AzaharArticSetup.plgInfo
Normal file
27
plugin/AzaharArticSetup.plgInfo
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Author: Nanquitas
|
||||||
|
|
||||||
|
Version: # Plugin version
|
||||||
|
Major: VERSION_MAJOR
|
||||||
|
Minor: VERSION_MINOR
|
||||||
|
Revision: VERSION_REVISION
|
||||||
|
|
||||||
|
Targets: # Low TitleId of games which are compatibles with this plugin (empty for all)
|
||||||
|
- 0x00020000
|
||||||
|
- 0x00021000
|
||||||
|
- 0x00022000
|
||||||
|
- 0x00026000
|
||||||
|
- 0x00027000
|
||||||
|
- 0x00028000
|
||||||
|
|
||||||
|
Title: Azahar Artic Setup Tool
|
||||||
|
|
||||||
|
Summary: Setup tool for Azahar Emulator
|
||||||
|
|
||||||
|
Description: |
|
||||||
|
Provides system files to the Azahar 3DS Emulator
|
||||||
|
|
||||||
|
Compatibility: Console
|
||||||
|
MemorySize: 2MiB
|
||||||
|
|
||||||
|
EventsSelfManaged: true
|
||||||
|
SwapNotNeeded: true
|
||||||
121
plugin/Makefile
Normal file
121
plugin/Makefile
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
include $(DEVKITARM)/3ds_rules
|
||||||
|
|
||||||
|
TARGET := AzaharArticSetup
|
||||||
|
PLGINFO := build/AzaharArticSetup.plgInfo
|
||||||
|
|
||||||
|
BUILD := build
|
||||||
|
INCLUDES := ArticProtocol/includes includes
|
||||||
|
SOURCES := ArticProtocol/sources sources sources/CTRPluginFramework
|
||||||
|
|
||||||
|
VERSION_MAJOR := 1
|
||||||
|
VERSION_MINOR := 2
|
||||||
|
VERSION_REVISION := 0
|
||||||
|
SERVER_PORT := 5543
|
||||||
|
|
||||||
|
IP := 19
|
||||||
|
FTP_HOST := 192.168.1.
|
||||||
|
FTP_PORT := "5000"
|
||||||
|
FTP_PATH := "luma/plugins"
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
|
||||||
|
|
||||||
|
CFLAGS := $(ARCH) -Os -mword-relocations \
|
||||||
|
-fomit-frame-pointer -ffunction-sections -fno-strict-aliasing
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__3DS__ -DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) \
|
||||||
|
-DVERSION_REVISION=$(VERSION_REVISION) -DSERVER_PORT=$(SERVER_PORT)
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++20
|
||||||
|
|
||||||
|
ASFLAGS := $(ARCH)
|
||||||
|
LDFLAGS := -T $(TOPDIR)/3gx.ld $(ARCH) -Os -Wl,--gc-sections,--strip-discarded
|
||||||
|
|
||||||
|
LIBS := -lctru
|
||||||
|
LIBDIRS := $(CTRULIB) $(PORTLIBS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
|
||||||
|
export LD := $(CXX)
|
||||||
|
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I $(CURDIR)/$(dir) ) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I $(dir)/include) \
|
||||||
|
-I $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L $(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all send
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD)
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(OUTPUT).3gx $(OUTPUT).elf
|
||||||
|
|
||||||
|
send:
|
||||||
|
@echo "Sending plugin over FTP"
|
||||||
|
@$(CURDIR)/sendfile.py $(TARGET).3gx $(FTP_PATH) "$(FTP_HOST)$(IP)" $(FTP_PORT) default.3gx
|
||||||
|
|
||||||
|
re: clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(OUTPUT).3gx : $(OFILES)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.3gx: %.elf
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo creating $(notdir $@)
|
||||||
|
@3gxtool -s $(word 1, $^) $(TOPDIR)/$(PLGINFO) $@
|
||||||
|
@mv $(OUTPUT).elf AzaharArticSetup.elf
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
BIN
plugin/images/logo.bclim
Normal file
BIN
plugin/images/logo.bclim
Normal file
Binary file not shown.
74
plugin/includes/BCLIM.hpp
Normal file
74
plugin/includes/BCLIM.hpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds.h"
|
||||||
|
#include "tuple"
|
||||||
|
#include "CTRPluginFramework/Vector.hpp"
|
||||||
|
#include "CTRPluginFramework/Rect.hpp"
|
||||||
|
#include "CTRPluginFramework/Color.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework {
|
||||||
|
class BCLIM {
|
||||||
|
public:
|
||||||
|
enum class TextureFormat : u32 {
|
||||||
|
L8 = 0,
|
||||||
|
A8 = 1,
|
||||||
|
LA4 = 2,
|
||||||
|
LA8 = 3,
|
||||||
|
HILO8 = 4,
|
||||||
|
RGB565 = 5,
|
||||||
|
RGB8 = 6,
|
||||||
|
RGBA5551 = 7,
|
||||||
|
RGBA4 = 8,
|
||||||
|
RGBA8 = 9,
|
||||||
|
ETC1 = 10,
|
||||||
|
ETC1A4 = 11,
|
||||||
|
L4 = 12,
|
||||||
|
A4 = 13,
|
||||||
|
};
|
||||||
|
struct Header {
|
||||||
|
u32 magic;
|
||||||
|
u16 endian;
|
||||||
|
u16 headerSize;
|
||||||
|
u32 version;
|
||||||
|
u32 fileSize;
|
||||||
|
u32 blockCount;
|
||||||
|
struct {
|
||||||
|
u32 magic;
|
||||||
|
u32 imagHeaderSize;
|
||||||
|
u16 width;
|
||||||
|
u16 height;
|
||||||
|
TextureFormat format;
|
||||||
|
} imag;
|
||||||
|
u32 dataLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
BCLIM(void* bclimData, u32 bclimSize) : BCLIM(bclimData, (Header*)((u32)bclimData + bclimSize - 0x28)) {}
|
||||||
|
BCLIM(void* bclimData, Header* bclimHeader) : data(bclimData), header(bclimHeader) {}
|
||||||
|
|
||||||
|
using ColorBlendCallback = Color(*)(const Color &, const Color &);
|
||||||
|
static std::pair<bool, ColorBlendCallback> OpaqueBlend() {
|
||||||
|
return std::make_pair(false, OpaqueBlendFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
using RenderBackend = void(*)(void*, bool, Color*, int posX, int posY);
|
||||||
|
static std::pair<void*, RenderBackend> RenderInterface() {
|
||||||
|
return std::make_pair(nullptr, RenderInterfaceBackend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(const Rect<int>& position, std::pair<void*, RenderBackend> backend = RenderInterface(), const Rect<int>& crop = Rect<int>(0, 0, INT32_MAX, INT32_MAX), const Rect<int>& limits = Rect<int>(0, 0, 400, 240), std::pair<bool, ColorBlendCallback> colorBlend = OpaqueBlend());
|
||||||
|
|
||||||
|
void* data;
|
||||||
|
private:
|
||||||
|
Header* header;
|
||||||
|
static const u8 textureTileOrder[16];
|
||||||
|
static const u8 etc1Modifiers[8][2];
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T GetDataAt(int offset) {
|
||||||
|
return *(T*)(((u32)data) + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RenderInterfaceBackend(void* usrData, bool isRead, Color* c, int posX, int posY);
|
||||||
|
|
||||||
|
static Color OpaqueBlendFunc(const Color& dst, const Color& src);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CTRPluginFramework/System/Mutex.hpp"
|
||||||
|
#include "CTRPluginFramework/System/Lock.hpp"
|
||||||
|
#include "CTRPluginFramework/Vector.hpp"
|
||||||
|
#include "CTRPluginFramework/Rect.hpp"
|
||||||
|
#include "CTRPluginFramework/Color.hpp"
|
||||||
37
plugin/includes/CTRPluginFramework/Clock.hpp
Normal file
37
plugin/includes/CTRPluginFramework/Clock.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds.h"
|
||||||
|
#include "CTRPluginFramework/Time.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Clock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Clock(void) : _startTime(GetCurrentTime()) {}
|
||||||
|
constexpr Clock(const Time& time) : _startTime(time) {}
|
||||||
|
|
||||||
|
__always_inline Time GetElapsedTime(void) const {
|
||||||
|
return (GetCurrentTime() - _startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
__always_inline bool HasTimePassed(const Time& time) const {
|
||||||
|
return (GetElapsedTime() >= time);
|
||||||
|
}
|
||||||
|
|
||||||
|
__always_inline Time Restart(void) {
|
||||||
|
const Time now = GetCurrentTime();
|
||||||
|
|
||||||
|
const Time ret = now - _startTime;
|
||||||
|
|
||||||
|
_startTime = now;
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Time _startTime;
|
||||||
|
|
||||||
|
static __always_inline Time GetCurrentTime(void)
|
||||||
|
{
|
||||||
|
return Ticks(svcGetSystemTick());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
67
plugin/includes/CTRPluginFramework/Color.hpp
Normal file
67
plugin/includes/CTRPluginFramework/Color.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds/types.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Color
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum class BlendMode
|
||||||
|
{
|
||||||
|
Alpha,
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Color(void) : a(255), b(0), g(0), r(0) {}
|
||||||
|
constexpr Color(u32 color) : raw(color) {}
|
||||||
|
constexpr Color(u8 red, u8 green, u8 blue, u8 alpha = 255) : a(alpha), b(blue), g(green), r(red) {}
|
||||||
|
|
||||||
|
inline u32 ToU32(void) const { return raw; };
|
||||||
|
Color &Fade(float fading);
|
||||||
|
Color Blend(const Color &color, BlendMode mode) const;
|
||||||
|
|
||||||
|
inline bool operator == (const Color &right) const {return raw == right.raw;}
|
||||||
|
inline bool operator != (const Color &right) const {return raw != right.raw;}
|
||||||
|
bool operator < (const Color &right) const;
|
||||||
|
bool operator <= (const Color &right) const;
|
||||||
|
bool operator > (const Color &right) const;
|
||||||
|
bool operator >= (const Color &right) const;
|
||||||
|
Color operator + (const Color &right) const;
|
||||||
|
Color operator - (const Color &right) const;
|
||||||
|
Color operator * (const Color &right) const;
|
||||||
|
Color &operator += (const Color &right);
|
||||||
|
Color &operator -= (const Color &right);
|
||||||
|
Color &operator *= (const Color &right);
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
char strColor[5] = { 0 };
|
||||||
|
|
||||||
|
strColor[0] = 0x1B;
|
||||||
|
strColor[1] = std::max((u8)1, r);
|
||||||
|
strColor[2] = std::max((u8)1, g);
|
||||||
|
strColor[3] = std::max((u8)1, b);
|
||||||
|
|
||||||
|
return strColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 raw;
|
||||||
|
struct // Match raw byte order
|
||||||
|
{
|
||||||
|
u8 a;
|
||||||
|
u8 b;
|
||||||
|
u8 g;
|
||||||
|
u8 r;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
143
plugin/includes/CTRPluginFramework/Rect.hpp
Normal file
143
plugin/includes/CTRPluginFramework/Rect.hpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "CTRPluginFramework/Vector.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class Rect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Rect();
|
||||||
|
Rect(const Vector<T>& leftTop, const Vector<T>& size);
|
||||||
|
Rect(const Vector<T>& leftTop, T width, T height);
|
||||||
|
Rect(T left, T top, const Vector<T>& size);
|
||||||
|
Rect(T left, T top, T width, T height);
|
||||||
|
template <typename U>
|
||||||
|
explicit Rect(const Rect<U>& rect);
|
||||||
|
|
||||||
|
bool Contains(T x, T y) const;
|
||||||
|
bool Contains(const Vector<T>& point) const;
|
||||||
|
bool Intersects(const Rect<T>& rect) const;
|
||||||
|
bool Intersects(const Rect<T>& rect, Rect<T>& intersect) const;
|
||||||
|
|
||||||
|
Vector<T> leftTop;
|
||||||
|
Vector<T> size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect() : leftTop(0, 0), size(0, 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(const Vector<T>& leftTopCorner, const Vector<T>& size)
|
||||||
|
{
|
||||||
|
leftTop = leftTopCorner;
|
||||||
|
this->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(const Vector<T>& leftTopCorner, T width, T height)
|
||||||
|
{
|
||||||
|
leftTop = leftTopCorner;
|
||||||
|
size.x = width;
|
||||||
|
size.y = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(T left, T top, const Vector<T>& size)
|
||||||
|
{
|
||||||
|
leftTop.x = left;
|
||||||
|
leftTop.y = top;
|
||||||
|
this->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Rect<T>::Rect(T left, T top, T width, T height)
|
||||||
|
{
|
||||||
|
leftTop.x = left;
|
||||||
|
leftTop.y = top;
|
||||||
|
size.x = width;
|
||||||
|
size.y = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename U>
|
||||||
|
Rect<T>::Rect(const Rect<U>& rect)
|
||||||
|
{
|
||||||
|
leftTop = reinterpret_cast<T>(rect.leftTop);
|
||||||
|
size = reinterpret_cast<T>(rect.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Contains(T x, T y) const
|
||||||
|
{
|
||||||
|
T minX = std::min(leftTop.x, leftTop.x + size.x);
|
||||||
|
T maxX = std::max(leftTop.x, leftTop.x + size.x);
|
||||||
|
T minY = std::min(leftTop.y, leftTop.y + size.y);
|
||||||
|
T maxY = std::max(leftTop.y, leftTop.y + size.y);
|
||||||
|
|
||||||
|
return (x >= minX && x < maxX
|
||||||
|
&& y >= minY && y < maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Contains(const Vector<T>& point) const
|
||||||
|
{
|
||||||
|
return (Contains(point.x, point.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Intersects(const Rect<T>& rect) const
|
||||||
|
{
|
||||||
|
Rect<T> intersect;
|
||||||
|
return (Intersects(rect, intersect));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Rect<T>::Intersects(const Rect<T> &rect, Rect<T> &intersect) const
|
||||||
|
{
|
||||||
|
T thisMinX = std::min(leftTop.x, leftTop.x + size.x);
|
||||||
|
T thisMaxX = std::max(leftTop.x, leftTop.x + size.x);
|
||||||
|
T thisMinY = std::min(leftTop.y, leftTop.y + size.y);
|
||||||
|
T thisMaxY = std::max(leftTop.y, leftTop.y + size.y);
|
||||||
|
T rectMinX = std::min(rect.leftTop.x, rect.leftTop.x + rect.size.x);
|
||||||
|
T rectMaxX = std::max(rect.leftTop.x, rect.leftTop.x + rect.size.x);
|
||||||
|
T rectMinY = std::min(rect.leftTop.y, rect.leftTop.y + rect.size.y);
|
||||||
|
T rectMaxY = std::max(rect.leftTop.y, rect.leftTop.y + rect.size.y);
|
||||||
|
|
||||||
|
T intersectLeftX = std::max(thisMinX, rectMinX);
|
||||||
|
T intersectLeftY = std::max(thisMinY, rectMinY);
|
||||||
|
T intersectRightX = std::min(thisMaxX, rectMaxX);
|
||||||
|
T intersectRightY = std::min(thisMaxY, rectMaxY);
|
||||||
|
|
||||||
|
if (intersectLeftX < intersectRightX && intersectLeftY < intersectRightY)
|
||||||
|
{
|
||||||
|
intersect = Rect<T>(intersectLeftX, intersectLeftY, intersectRightX - intersectLeftX,
|
||||||
|
intersectRightY - intersectLeftY);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
intersect = Rect<T>(0, 0, 0, 0);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator ==(Rect<T> &left, Rect<T> &right)
|
||||||
|
{
|
||||||
|
return (left.leftTop == right.leftTop
|
||||||
|
&& left.size == right.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator !=(Rect<T> &left, Rect<T> &right)
|
||||||
|
{
|
||||||
|
return (left.leftTop != right.leftTop
|
||||||
|
&& left.size != right.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Rect<unsigned int> UIntRect;
|
||||||
|
typedef Rect<int> IntRect;
|
||||||
|
typedef Rect<float> FloatRect;
|
||||||
|
}
|
||||||
54
plugin/includes/CTRPluginFramework/System/Lock.hpp
Normal file
54
plugin/includes/CTRPluginFramework/System/Lock.hpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef CTRPLUGINFRAMEWORK_SYSTEM_LOCK_HPP
|
||||||
|
#define CTRPLUGINFRAMEWORK_SYSTEM_LOCK_HPP
|
||||||
|
|
||||||
|
#include "3ds.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Mutex;
|
||||||
|
class Lock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline explicit Lock(LightLock &llock) :
|
||||||
|
_type{LIGHTLOCK}, _llock{&llock}
|
||||||
|
{
|
||||||
|
LightLock_Lock(_llock);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit Lock(RecursiveLock &rlock) :
|
||||||
|
_type{RECLOCK}, _rlock{&rlock}
|
||||||
|
{
|
||||||
|
RecursiveLock_Lock(_rlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit Lock(Mutex &mutex) :
|
||||||
|
_type{MUTEX}, _mutex{&mutex}
|
||||||
|
{
|
||||||
|
mutex.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~Lock(void)
|
||||||
|
{
|
||||||
|
if (_type == LIGHTLOCK)
|
||||||
|
LightLock_Unlock(_llock);
|
||||||
|
else if (_type == RECLOCK)
|
||||||
|
RecursiveLock_Unlock(_rlock);
|
||||||
|
else if (_type == MUTEX)
|
||||||
|
_mutex->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const constexpr u32 LIGHTLOCK = 1;
|
||||||
|
static const constexpr u32 RECLOCK = 2;
|
||||||
|
static const constexpr u32 MUTEX = 3;
|
||||||
|
const u32 _type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
LightLock *_llock;
|
||||||
|
RecursiveLock *_rlock;
|
||||||
|
Mutex *_mutex;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
41
plugin/includes/CTRPluginFramework/System/Mutex.hpp
Normal file
41
plugin/includes/CTRPluginFramework/System/Mutex.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef CTRPLUGINFRAMEWORK_SYSTEM_MUTEX_HPP
|
||||||
|
#define CTRPLUGINFRAMEWORK_SYSTEM_MUTEX_HPP
|
||||||
|
|
||||||
|
#include "3ds.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Mutex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline Mutex(void) {
|
||||||
|
RecursiveLock_Init(&_lock);
|
||||||
|
}
|
||||||
|
inline ~Mutex(void) {
|
||||||
|
// I suppose that we can "force" unlock the mutex
|
||||||
|
if (_lock.counter > 0)
|
||||||
|
{
|
||||||
|
_lock.counter = 1;
|
||||||
|
RecursiveLock_Unlock(&_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Lock(void) {
|
||||||
|
RecursiveLock_Lock(&_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true on failure
|
||||||
|
inline bool TryLock(void) {
|
||||||
|
return RecursiveLock_TryLock(&_lock) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unlock(void) {
|
||||||
|
RecursiveLock_Unlock(&_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RecursiveLock _lock;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
205
plugin/includes/CTRPluginFramework/Time.hpp
Normal file
205
plugin/includes/CTRPluginFramework/Time.hpp
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "3ds/types.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
class Time
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
constexpr Time(void) : _ticks(0) {}
|
||||||
|
|
||||||
|
|
||||||
|
float AsSeconds(void) const;
|
||||||
|
|
||||||
|
int AsMilliseconds(void) const;
|
||||||
|
|
||||||
|
s64 AsMicroseconds(void) const;
|
||||||
|
|
||||||
|
inline s64 AsTicks(void) const { return _ticks; }
|
||||||
|
|
||||||
|
static const Time Zero; ///< Predefined "zero" time value
|
||||||
|
|
||||||
|
static constexpr u32 TicksPerSecond = 268111856U;
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
friend constexpr Time Seconds(float amount);
|
||||||
|
friend constexpr Time Milliseconds(int amount);
|
||||||
|
friend constexpr Time Microseconds(s64 amount);
|
||||||
|
friend constexpr Time Ticks(s64 amount);
|
||||||
|
|
||||||
|
constexpr Time(s64 ticks) : _ticks(ticks) {}
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
|
||||||
|
s64 _ticks;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Time Seconds(float amount)
|
||||||
|
{
|
||||||
|
return (Time(static_cast<s64>(amount * Time::TicksPerSecond)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constexpr Time Milliseconds(int amount)
|
||||||
|
{
|
||||||
|
return (Time(static_cast<s64>(amount * (Time::TicksPerSecond / 1000.f))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constexpr Time Microseconds(s64 amount)
|
||||||
|
{
|
||||||
|
return (Time(static_cast<s64>(amount * (Time::TicksPerSecond / 1000000.f))));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Time Ticks(s64 amount)
|
||||||
|
{
|
||||||
|
return (Time(amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator ==(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() == right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator !=(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() != right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator <(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() < right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator >(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() > right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator <=(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() <= right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator >=(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsTicks() >= right.AsTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Time operator -(const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(-right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator +(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(left.AsTicks() + right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator +=(Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left = left + right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator -(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(left.AsTicks() - right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator -=(Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return left = left - right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(const Time& left, float right)
|
||||||
|
{
|
||||||
|
return (Seconds(left.AsSeconds() * right));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(const Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (Microseconds(left.AsMicroseconds() * right));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(float left, const Time& right)
|
||||||
|
{
|
||||||
|
return (right * left);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator *(s64 left, const Time& right)
|
||||||
|
{
|
||||||
|
return (right * left);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator *=(Time& left, float right)
|
||||||
|
{
|
||||||
|
return (left = left * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator *=(Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (left = left * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator /(const Time& left, float right)
|
||||||
|
{
|
||||||
|
return Seconds(left.AsSeconds() / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator /(const Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (Microseconds(left.AsMicroseconds() / right));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator /=(Time& left, float right)
|
||||||
|
{
|
||||||
|
return (left = left / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator /=(Time& left, s64 right)
|
||||||
|
{
|
||||||
|
return (left = left / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline float operator /(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left.AsSeconds() / right.AsSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time operator %(const Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (Ticks(left.AsTicks() % right.AsTicks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Time& operator %=(Time& left, const Time& right)
|
||||||
|
{
|
||||||
|
return (left = left % right);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
124
plugin/includes/CTRPluginFramework/Vector.hpp
Normal file
124
plugin/includes/CTRPluginFramework/Vector.hpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds/types.h"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class Vector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vector();
|
||||||
|
Vector(T x, T y);
|
||||||
|
template <typename U>
|
||||||
|
explicit Vector(const Vector<U> &vector);
|
||||||
|
|
||||||
|
T x;
|
||||||
|
T y;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T>::Vector() : x(0), y(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T>::Vector(T x, T y) : x(x), y(y)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename U>
|
||||||
|
Vector<T>::Vector(const Vector<U> &vector) : x(static_cast<T>(vector.x)), y(static_cast<T>(vector.y))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator - (const Vector<T> &vector)
|
||||||
|
{
|
||||||
|
return (Vector<T>(-vector.x, -vector.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator - (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x - right.x, left.y - right.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator -= (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
left.x -= right.x;
|
||||||
|
left.y -= right.y;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator + (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x + right.x, left.y + right.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator += (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
left.x += right.x;
|
||||||
|
left.y += right.y;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator * (const Vector<T> &left, T right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x * right, left.y * right));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator * (const T left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(right.x * left, right.y * left));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator *= (Vector<T> &left, const T right)
|
||||||
|
{
|
||||||
|
left.x *= right;
|
||||||
|
left.y *= right;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> operator / (const Vector<T> &left, const T right)
|
||||||
|
{
|
||||||
|
return (Vector<T>(left.x / right, left.y / right));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> &operator /= (Vector<T> &left, const T right)
|
||||||
|
{
|
||||||
|
left.x /= right;
|
||||||
|
left.y /= right;
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator <= (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (left.x <= right.x
|
||||||
|
&& left.y <= right.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator >= (const Vector<T> &left, const Vector<T> &right)
|
||||||
|
{
|
||||||
|
return (left.x >= right.x
|
||||||
|
&& left.y >= right.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Vector<unsigned int> UIntVector;
|
||||||
|
typedef Vector<int> IntVector;
|
||||||
|
typedef Vector<float> FloatVector;
|
||||||
|
typedef Vector<signed short> shortVector;
|
||||||
|
}
|
||||||
6
plugin/includes/Intellisense.hpp
Normal file
6
plugin/includes/Intellisense.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Only used by Visual Studio Intellisense
|
||||||
|
|
||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 0
|
||||||
|
#define VERSION_REVISION 1
|
||||||
|
#define SERVER_PORT 5543
|
||||||
5
plugin/includes/Main.hpp
Normal file
5
plugin/includes/Main.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "3ds.h"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
extern Logger logger;
|
||||||
154
plugin/includes/csvc.h
Normal file
154
plugin/includes/csvc.h
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
/* This paricular file is licensed under the following terms: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
|
||||||
|
* for any damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
|
||||||
|
* and redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
||||||
|
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||||
|
* This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
/// Operations for svcControlService
|
||||||
|
typedef enum ServiceOp
|
||||||
|
{
|
||||||
|
SERVICEOP_STEAL_CLIENT_SESSION = 0, ///< Steal a client session given a service or global port name
|
||||||
|
SERVICEOP_GET_NAME, ///< Get the name of a service or global port given a client or session handle
|
||||||
|
} ServiceOp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Executes a function in supervisor mode, using the supervisor-mode stack.
|
||||||
|
* @param func Function to execute.
|
||||||
|
* @param ... Function parameters, up to 3 registers.
|
||||||
|
*/
|
||||||
|
Result svcCustomBackdoor(void *func, ...);
|
||||||
|
|
||||||
|
///@name I/O
|
||||||
|
///@{
|
||||||
|
/**
|
||||||
|
* @brief Gives the physical address corresponding to a virtual address.
|
||||||
|
* @param VA Virtual address.
|
||||||
|
* @param writeCheck whether to check if the VA is writable in supervisor mode
|
||||||
|
* @return The corresponding physical address, or NULL.
|
||||||
|
*/
|
||||||
|
u32 svcConvertVAToPA(const void *VA, bool writeCheck);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flushes a range of the data cache (L2C included).
|
||||||
|
* @param addr Start address.
|
||||||
|
* @param len Length of the range.
|
||||||
|
*/
|
||||||
|
void svcFlushDataCacheRange(void *addr, u32 len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flushes the data cache entirely (L2C included).
|
||||||
|
*/
|
||||||
|
void svcFlushEntireDataCache(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Invalidates a range of the instruction cache.
|
||||||
|
* @param addr Start address.
|
||||||
|
* @param len Length of the range.
|
||||||
|
*/
|
||||||
|
void svcInvalidateInstructionCacheRange(void *addr, u32 len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Invalidates the data cache entirely.
|
||||||
|
*/
|
||||||
|
void svcInvalidateEntireInstructionCache(void);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
///@name Memory management
|
||||||
|
///@{
|
||||||
|
/**
|
||||||
|
* @brief Maps a block of process memory.
|
||||||
|
* @param dstProcessHandle Handle of the process to map the memory in (destination)
|
||||||
|
* @param destAddress Address of the mapped block in the current process.
|
||||||
|
* @param srcProcessHandle Handle of the process to map the memory from (source)
|
||||||
|
* @param srcAddress Address of the mapped block in the source process.
|
||||||
|
* @param size Size of the block of the memory to map (truncated to a multiple of 0x1000 bytes).
|
||||||
|
*/
|
||||||
|
Result svcMapProcessMemoryEx(Handle dstProcessHandle, u32 destAddress, Handle srcProcessHandle, u32 vaSrc, u32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unmaps a block of process memory.
|
||||||
|
* @param process Handle of the process to unmap the memory from
|
||||||
|
* @param destAddress Address of the block of memory to unmap
|
||||||
|
* @param size Size of the block of memory to unmap (truncated to a multiple of 0x1000 bytes).
|
||||||
|
* This function should only be used to unmap memory mapped with svcMapProcessMemoryEx
|
||||||
|
*/
|
||||||
|
Result svcUnmapProcessMemoryEx(Handle process, u32 destAddress, u32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Controls memory mapping, with the choice to use region attributes or not.
|
||||||
|
* @param[out] addr_out The virtual address resulting from the operation. Usually the same as addr0.
|
||||||
|
* @param addr0 The virtual address to be used for the operation.
|
||||||
|
* @param addr1 The virtual address to be (un)mirrored by @p addr0 when using @ref MEMOP_MAP or @ref MEMOP_UNMAP.
|
||||||
|
* It has to be pointing to a RW memory.
|
||||||
|
* Use NULL if the operation is @ref MEMOP_FREE or @ref MEMOP_ALLOC.
|
||||||
|
* @param size The requested size for @ref MEMOP_ALLOC and @ref MEMOP_ALLOC_LINEAR.
|
||||||
|
* @param op Operation flags. See @ref MemOp.
|
||||||
|
* @param perm A combination of @ref MEMPERM_READ and @ref MEMPERM_WRITE. Using MEMPERM_EXECUTE will return an error.
|
||||||
|
* Value 0 is used when unmapping memory.
|
||||||
|
* @param isLoader Whether to use the region attributes
|
||||||
|
* If a memory is mapped for two or more addresses, you have to use MEMOP_UNMAP before being able to MEMOP_FREE it.
|
||||||
|
* MEMOP_MAP will fail if @p addr1 was already mapped to another address.
|
||||||
|
*
|
||||||
|
* @sa svcControlMemory
|
||||||
|
*/
|
||||||
|
Result svcControlMemoryEx(u32* addr_out, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
///@name System
|
||||||
|
///@{
|
||||||
|
/**
|
||||||
|
* @brief Performs actions related to services or global handles.
|
||||||
|
* @param op The operation to perform, see @ref ServiceOp.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* svcControlService(SERVICEOP_GET_NAME, (char [12])outName, (Handle)clientOrSessionHandle);
|
||||||
|
* svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, (Handle *)&outHandle, (const char *)name);
|
||||||
|
*/
|
||||||
|
Result svcControlService(ServiceOp op, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy a handle from a process to another one.
|
||||||
|
* @param[out] out The output handle.
|
||||||
|
* @param outProcess Handle of the process of the output handle.
|
||||||
|
* @param in The input handle. Pseudo-handles are not accepted.
|
||||||
|
* @param inProcess Handle of the process of the input handle.
|
||||||
|
*/
|
||||||
|
Result svcCopyHandle(Handle *out, Handle outProcess, Handle in, Handle inProcess);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the address and class name of the underlying kernel object corresponding to a handle.
|
||||||
|
* @param[out] outKAddr The output kernel address.
|
||||||
|
* @param[out] outName Output class name. The buffer should be large enough to contain it.
|
||||||
|
* @param in The input handle.
|
||||||
|
*/
|
||||||
|
Result svcTranslateHandle(u32 *outKAddr, char *outClassName, Handle in);
|
||||||
|
|
||||||
|
/// Operations for svcControlProcess
|
||||||
|
typedef enum ProcessOp
|
||||||
|
{
|
||||||
|
PROCESSOP_GET_ALL_HANDLES, ///< List all handles of the process, varg3 can be either 0 to fetch all handles, or token of the type to fetch
|
||||||
|
///< svcControlProcess(handle, PROCESSOP_GET_ALL_HANDLES, (u32)&outBuf, 0)
|
||||||
|
PROCESSOP_SET_MMU_TO_RWX, ///< Set the whole memory of the process with rwx access
|
||||||
|
///< svcControlProcess(handle, PROCESSOP_SET_MMU_TO_RWX, 0, 0)
|
||||||
|
PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT,
|
||||||
|
PROCESSOP_GET_ON_EXIT_EVENT,
|
||||||
|
PROCESSOP_GET_PA_FROM_VA, ///< Get the physical address of the va within the process
|
||||||
|
///< svcControlProcess(handle, PROCESSOP_GET_PA_FROM_VA, (u32)&outPa, va)
|
||||||
|
} ProcessOp;
|
||||||
|
|
||||||
|
Result svcControlProcess(Handle process, ProcessOp op, u32 varg2, u32 varg3);
|
||||||
|
///@}
|
||||||
9
plugin/includes/logo.h
Normal file
9
plugin/includes/logo.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* Generated by bin2c, do not edit manually */
|
||||||
|
#ifndef ____includes_logo_h_included
|
||||||
|
#define ____includes_logo_h_included
|
||||||
|
|
||||||
|
/* Contents of file .\data\logo.bin */
|
||||||
|
extern const long int __data_logo_bin_size;
|
||||||
|
extern const unsigned char __data_logo_bin[32808];
|
||||||
|
|
||||||
|
#endif /* ____includes_logo_h_included */
|
||||||
134
plugin/includes/nim_extheader.h
Normal file
134
plugin/includes/nim_extheader.h
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/* Generated by bin2c, do not edit manually */
|
||||||
|
|
||||||
|
/* Contents of file extheader.bin */
|
||||||
|
const long int nim_extheader_bin_size = 2048;
|
||||||
|
const unsigned char nim_extheader_bin[2048] = {
|
||||||
|
0x6E, 0x69, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00,
|
||||||
|
0x00, 0x00, 0x10, 0x00, 0x51, 0x00, 0x00, 0x00, 0x7C, 0x01, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||||||
|
0x00, 0x10, 0x15, 0x00, 0x05, 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x60, 0x15, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA8, 0x09, 0x00, 0x00, 0xC8, 0x02, 0x13, 0x00,
|
||||||
|
0x02, 0x24, 0x00, 0x00, 0x30, 0x01, 0x04, 0x00, 0x02, 0x15, 0x00, 0x00, 0x30, 0x01, 0x04, 0x00,
|
||||||
|
0x02, 0x17, 0x00, 0x00, 0x30, 0x01, 0x04, 0x00, 0x02, 0x29, 0x00, 0x00, 0x30, 0x01, 0x04, 0x00,
|
||||||
|
0x02, 0x2F, 0x00, 0x00, 0x30, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x2C, 0x00, 0x00, 0x30, 0x01, 0x04, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0x2C, 0x00, 0x00, 0x30, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x3D,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x66, 0x73, 0x3A, 0x55, 0x53, 0x45, 0x52, 0x00, 0x61, 0x6D, 0x3A, 0x6E, 0x65, 0x74, 0x00, 0x00,
|
||||||
|
0x61, 0x63, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x43, 0x00, 0x00,
|
||||||
|
0x63, 0x66, 0x67, 0x3A, 0x73, 0x00, 0x00, 0x00, 0x70, 0x74, 0x6D, 0x3A, 0x73, 0x00, 0x00, 0x00,
|
||||||
|
0x70, 0x74, 0x6D, 0x3A, 0x67, 0x65, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||||
|
0x4E, 0x9F, 0xFA, 0xF0, 0xFF, 0xBF, 0xFF, 0xF1, 0xE7, 0x3F, 0x80, 0xF2, 0xFD, 0x00, 0x00, 0xF3,
|
||||||
|
0x80, 0x03, 0x00, 0xFF, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||||
|
0x02, 0x20, 0xE3, 0x4B, 0xE4, 0x26, 0xA3, 0x5F, 0x83, 0x17, 0x88, 0xB5, 0x0F, 0xDA, 0x7A, 0x77,
|
||||||
|
0xDB, 0xC7, 0x03, 0x50, 0xB0, 0xEC, 0xE5, 0x9B, 0x47, 0x0B, 0x2F, 0x21, 0x97, 0xF7, 0x81, 0xF5,
|
||||||
|
0x57, 0xAB, 0xBF, 0x1D, 0xA0, 0x96, 0x72, 0x2A, 0x6F, 0x6F, 0x06, 0x51, 0xC3, 0x86, 0x4C, 0x31,
|
||||||
|
0x34, 0x10, 0x81, 0xDC, 0x61, 0x10, 0x73, 0x57, 0xEF, 0xCC, 0x49, 0x09, 0x46, 0x84, 0x9C, 0xEA,
|
||||||
|
0xFA, 0xDB, 0xC6, 0xF7, 0x8F, 0xCE, 0x40, 0x9F, 0xD0, 0x38, 0x90, 0xE4, 0x2D, 0xA1, 0xAC, 0x51,
|
||||||
|
0xF0, 0x9D, 0xF8, 0xBC, 0xC1, 0xDC, 0xD2, 0xCB, 0xDE, 0x60, 0x25, 0x3A, 0xB5, 0x12, 0xC5, 0x21,
|
||||||
|
0x1E, 0x41, 0x2C, 0x56, 0x8F, 0xB0, 0x8A, 0x8B, 0x0E, 0xF5, 0x40, 0x73, 0xD1, 0x17, 0x3F, 0x2B,
|
||||||
|
0x8E, 0x34, 0x3C, 0x55, 0xC2, 0xC4, 0x74, 0x74, 0x84, 0x2E, 0xDC, 0xC6, 0xB5, 0x95, 0x71, 0x7C,
|
||||||
|
0xBA, 0xF8, 0x3B, 0xC8, 0x31, 0x4A, 0x85, 0x7A, 0xD1, 0x76, 0xAD, 0x41, 0xBD, 0xAA, 0x9A, 0xE8,
|
||||||
|
0x81, 0x0A, 0x64, 0x99, 0x86, 0x41, 0x3A, 0xB2, 0xEB, 0x2F, 0xB7, 0x52, 0x3F, 0xDA, 0x2C, 0x60,
|
||||||
|
0x70, 0x45, 0xAB, 0x0F, 0x2C, 0x31, 0xD3, 0x35, 0x6E, 0x02, 0x40, 0x3C, 0x63, 0x58, 0x8F, 0x28,
|
||||||
|
0x5F, 0xD2, 0x7C, 0xDF, 0x42, 0xAA, 0x5E, 0x5D, 0x4D, 0x50, 0x61, 0xA9, 0x2A, 0x81, 0x49, 0xA7,
|
||||||
|
0xA3, 0x76, 0xE6, 0xA4, 0x33, 0x08, 0xAD, 0x93, 0xF5, 0x18, 0x54, 0x50, 0xFC, 0xAE, 0x66, 0x44,
|
||||||
|
0x92, 0x23, 0xB5, 0xF6, 0x2F, 0xAE, 0x57, 0xCB, 0x42, 0x92, 0x56, 0xAC, 0xE4, 0xBE, 0x83, 0xDB,
|
||||||
|
0x05, 0x5E, 0x18, 0x2E, 0x1D, 0xB4, 0x35, 0x8D, 0xE5, 0x3C, 0xDC, 0xB3, 0x90, 0x9D, 0x6C, 0xDB,
|
||||||
|
0x0F, 0xC0, 0xC3, 0xD8, 0x4F, 0xA5, 0xF3, 0x79, 0x8A, 0xC4, 0xD9, 0x13, 0x07, 0x06, 0x9F, 0xC1,
|
||||||
|
0xA6, 0x92, 0x3F, 0xDE, 0x62, 0x6C, 0x2B, 0xBC, 0x70, 0x94, 0x81, 0x79, 0x80, 0xF6, 0x6E, 0xF9,
|
||||||
|
0xBD, 0x6D, 0xC0, 0xDD, 0xA8, 0x7D, 0x54, 0xE3, 0xC8, 0x0D, 0x0E, 0xDA, 0x5F, 0x4C, 0x23, 0x75,
|
||||||
|
0x11, 0xE2, 0x0F, 0x16, 0x0A, 0x48, 0x5D, 0xE9, 0xD3, 0x5F, 0x7E, 0x8B, 0x55, 0x9B, 0xC1, 0xC9,
|
||||||
|
0xA4, 0xED, 0xA6, 0x1A, 0x3A, 0xFD, 0xA7, 0x82, 0x3B, 0x1C, 0xE3, 0x73, 0xE3, 0xBA, 0xC7, 0x86,
|
||||||
|
0x05, 0x93, 0xE4, 0x0A, 0xC1, 0x6C, 0x3E, 0xC8, 0x87, 0x11, 0x5F, 0x98, 0xCC, 0x76, 0x23, 0xA3,
|
||||||
|
0xA5, 0x79, 0x95, 0x0A, 0xDD, 0x7D, 0x27, 0x0F, 0x26, 0x85, 0x0A, 0xE9, 0x4F, 0x2D, 0x23, 0x44,
|
||||||
|
0xF7, 0xA5, 0xE8, 0x7F, 0x17, 0x7F, 0x65, 0x5F, 0x4D, 0xCD, 0x6D, 0xF2, 0xDB, 0x64, 0xF4, 0x30,
|
||||||
|
0xD1, 0x57, 0x2B, 0x92, 0x34, 0xDA, 0x60, 0xB5, 0xF7, 0x26, 0x4A, 0xC3, 0x66, 0xC0, 0x27, 0x35,
|
||||||
|
0xD5, 0xF2, 0xB5, 0xB0, 0xB0, 0xE6, 0xB3, 0xC9, 0x92, 0xEB, 0x8F, 0x40, 0x38, 0x9C, 0xE4, 0x30,
|
||||||
|
0x9C, 0x13, 0xF9, 0x2F, 0x5B, 0x90, 0x67, 0x30, 0xE9, 0x44, 0xD9, 0x7F, 0x8C, 0x09, 0x34, 0xEE,
|
||||||
|
0x89, 0x67, 0xD6, 0x00, 0xA1, 0x54, 0xB1, 0xD5, 0x10, 0x72, 0xD5, 0xDA, 0x15, 0x1E, 0x50, 0xB4,
|
||||||
|
0x25, 0xD7, 0x82, 0xD3, 0xAA, 0x0B, 0xD0, 0x65, 0x77, 0x8D, 0x5D, 0x07, 0xFF, 0x9B, 0x8E, 0xF0,
|
||||||
|
0x8C, 0x37, 0x23, 0x13, 0x6C, 0xFD, 0xF8, 0xE6, 0xB6, 0x8E, 0xB2, 0x89, 0xAB, 0x44, 0x69, 0x30,
|
||||||
|
0x96, 0x50, 0x8B, 0x88, 0xCB, 0xF4, 0x47, 0x60, 0x7D, 0xC5, 0xA7, 0xAB, 0x3B, 0x45, 0x7E, 0xDF,
|
||||||
|
0x8C, 0x6D, 0x0C, 0x2B, 0x3F, 0x40, 0x3A, 0x55, 0xB2, 0xF7, 0xDF, 0x26, 0x21, 0xBE, 0xC5, 0x5F,
|
||||||
|
0x82, 0xCF, 0xE2, 0x51, 0x74, 0x43, 0xEC, 0x57, 0xA1, 0x04, 0x8C, 0x19, 0x4F, 0x86, 0xB9, 0x49,
|
||||||
|
0xFF, 0x2C, 0x00, 0xF0, 0x30, 0x01, 0x04, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x02,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x66, 0x73, 0x3A, 0x55, 0x53, 0x45, 0x52, 0x00, 0x61, 0x6D, 0x3A, 0x6E, 0x65, 0x74, 0x00, 0x00,
|
||||||
|
0x61, 0x63, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x43, 0x00, 0x00,
|
||||||
|
0x63, 0x66, 0x67, 0x3A, 0x73, 0x00, 0x00, 0x00, 0x70, 0x74, 0x6D, 0x3A, 0x73, 0x00, 0x00, 0x00,
|
||||||
|
0x70, 0x74, 0x6D, 0x3A, 0x67, 0x65, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||||
|
0x4E, 0x9F, 0xFA, 0xF0, 0xFF, 0xBF, 0xFF, 0xF1, 0xE7, 0x3F, 0x80, 0xF2, 0xFD, 0x00, 0x00, 0xF3,
|
||||||
|
0x80, 0x03, 0x00, 0xFF, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
|
||||||
|
};
|
||||||
79
plugin/includes/plgldr.h
Normal file
79
plugin/includes/plgldr.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
#define MAX_BUFFER (50)
|
||||||
|
#define MAX_ITEMS_COUNT (64)
|
||||||
|
#define HeaderMagic (0x24584733) /* "3GX$" */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool noFlash;
|
||||||
|
u8 pluginMemoryStrategy;
|
||||||
|
u8 persistent;
|
||||||
|
u32 lowTitleId;
|
||||||
|
char path[256];
|
||||||
|
u32 config[32];
|
||||||
|
} PluginLoadParameters;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 nbItems;
|
||||||
|
u8 states[MAX_ITEMS_COUNT];
|
||||||
|
char title[MAX_BUFFER];
|
||||||
|
char items[MAX_ITEMS_COUNT][MAX_BUFFER];
|
||||||
|
char hints[MAX_ITEMS_COUNT][MAX_BUFFER];
|
||||||
|
} PluginMenu;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PLG_WAIT = -1,
|
||||||
|
PLG_OK = 0,
|
||||||
|
PLG_SLEEP_ENTRY = 1,
|
||||||
|
PLG_SLEEP_EXIT = 2,
|
||||||
|
PLG_ABOUT_TO_SWAP = 3,
|
||||||
|
PLG_ABOUT_TO_EXIT = 4,
|
||||||
|
PLG_HOME_ENTER = 5,
|
||||||
|
PLG_HOME_EXIT = 6,
|
||||||
|
} PLG_Event;
|
||||||
|
|
||||||
|
typedef struct ///< Defined by Luma3DS plugin loader
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 version;
|
||||||
|
u32 heapVA;
|
||||||
|
u32 heapSize;
|
||||||
|
u32 exeSize; // Include sizeof(PluginHeader) + .text + .rodata + .data + .bss (0x1000 aligned too)
|
||||||
|
u32 isDefaultPlugin;
|
||||||
|
s32* plgldrEvent; ///< Used for synchronization
|
||||||
|
s32* plgldrReply; ///< Used for synchronization
|
||||||
|
u8 notifyHomeEvent;
|
||||||
|
u8 padding[3];
|
||||||
|
u32 reserved[23];
|
||||||
|
u32 config[32];
|
||||||
|
} PluginHeader;
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*OnPlgLdrEventCb_t)(s32 eventType);
|
||||||
|
|
||||||
|
Result plgLdrInit(void);
|
||||||
|
void plgLdrExit(void);
|
||||||
|
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled);
|
||||||
|
Result PLGLDR__SetPluginLoaderState(bool enabled);
|
||||||
|
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters);
|
||||||
|
Result PLGLDR__DisplayMenu(PluginMenu *menu);
|
||||||
|
Result PLGLDR__DisplayMessage(const char *title, const char *body);
|
||||||
|
Result PLGLDR__DisplayErrMessage(const char *title, const char *body, u32 error);
|
||||||
|
Result PLGLDR__GetVersion(u32 *version);
|
||||||
|
Result PLGLDR__GetPluginPath(char *path);
|
||||||
|
Result PLGLDR__SetRosalinaMenuBlock(bool shouldBlock);
|
||||||
|
Result PLGLDR__SetSwapSettings(const char* swapPath, void* encFunc, void* decFunc, void* args);
|
||||||
|
void PLGLDR__SetEventCallback(OnPlgLdrEventCb_t cb);
|
||||||
|
void PLGLDR__Status(void);
|
||||||
|
Result PLGLDR__ClearPluginLoadParameters();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
57
plugin/sendfile.py
Normal file
57
plugin/sendfile.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env Python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import ftplib
|
||||||
|
import datetime
|
||||||
|
from ftplib import FTP
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# sendfile.py "filename" "ftppath" "host" "ip"
|
||||||
|
|
||||||
|
def printf(string):
|
||||||
|
print(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S') + " : " + string);
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("");
|
||||||
|
printf("FTP File Sender\n")
|
||||||
|
try:
|
||||||
|
filename = sys.argv[1]
|
||||||
|
path = sys.argv[2]
|
||||||
|
host = sys.argv[3]
|
||||||
|
port = sys.argv[4]
|
||||||
|
destfile = sys.argv[5]
|
||||||
|
|
||||||
|
ftp = FTP()
|
||||||
|
printf("Connecting to " + host + ":" + port);
|
||||||
|
ftp.connect(host, int(port), timeout=3);
|
||||||
|
printf("Connected");
|
||||||
|
|
||||||
|
printf("Opening " + filename);
|
||||||
|
file = open(sys.argv[1], "rb");
|
||||||
|
printf("Success");
|
||||||
|
|
||||||
|
except IOError as e:
|
||||||
|
printf("/!\ An error occured. /!\ ");
|
||||||
|
|
||||||
|
printf("Moving to: ftp:/" + path);
|
||||||
|
try:
|
||||||
|
ftp.cwd(path);
|
||||||
|
except IOError:
|
||||||
|
try:
|
||||||
|
ftp.mkd(path);
|
||||||
|
ftp.cwd(path);
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
printf("Sending file");
|
||||||
|
ftp.storbinary('STOR '+ destfile, file);
|
||||||
|
printf("Done")
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
ftp.quit();
|
||||||
|
printf("Disconnected");
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
printf("/!\ An error occured. /!\ ");
|
||||||
86
plugin/sources/3gx_crt0.s
Normal file
86
plugin/sources/3gx_crt0.s
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
--------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ 3DS processor selection
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.cpu mpcore
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.section ".crt0","ax"
|
||||||
|
.global _start, __service_ptr, __apt_appid, __ctru_heap_size, __ctru_linear_heap_size, __system_arglist, __system_runflags
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.align 2
|
||||||
|
.arm
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
b startup
|
||||||
|
.ascii "_prm"
|
||||||
|
__service_ptr:
|
||||||
|
.word 0 @ Pointer to service handle override list -- if non-NULL it is assumed that we have been launched from a homebrew launcher
|
||||||
|
__apt_appid:
|
||||||
|
.word 0x300 @ Program APPID
|
||||||
|
__ctru_heap_size:
|
||||||
|
.word 24*1024*1024 @ Default heap size (24 MiB)
|
||||||
|
__ctru_linear_heap_size:
|
||||||
|
.word 24*1024*1024 @ Default linear heap size (24 MiB)
|
||||||
|
__system_arglist:
|
||||||
|
.word 0 @ Pointer to argument list (argc (u32) followed by that many NULL terminated strings)
|
||||||
|
__system_runflags:
|
||||||
|
.word 0 @ Flags to signal runtime restrictions to ctrulib
|
||||||
|
startup:
|
||||||
|
@ Restore plugin loader state, including the pushed stack registers
|
||||||
|
add sp, sp, #4
|
||||||
|
ldmfd sp!, {r0}
|
||||||
|
msr cpsr, r0
|
||||||
|
ldmfd sp!, {r0-r12}
|
||||||
|
mov lr, #0
|
||||||
|
|
||||||
|
@ Save return address
|
||||||
|
mov r4, lr
|
||||||
|
|
||||||
|
@ Clear the BSS section
|
||||||
|
ldr r0, =__bss_start__
|
||||||
|
ldr r1, =__bss_end__
|
||||||
|
sub r1, r1, r0
|
||||||
|
bl ClearMem
|
||||||
|
|
||||||
|
@ System initialization
|
||||||
|
mov r0, r4
|
||||||
|
bl initSystem
|
||||||
|
|
||||||
|
@ Set up argc/argv arguments for main()
|
||||||
|
ldr r0, =__system_argc
|
||||||
|
ldr r1, =__system_argv
|
||||||
|
ldr r0, [r0]
|
||||||
|
ldr r1, [r1]
|
||||||
|
|
||||||
|
@ Jump to user code
|
||||||
|
ldr r3, =main
|
||||||
|
ldr lr, =exit
|
||||||
|
bx r3
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ Clear memory to 0x00 if length != 0
|
||||||
|
@ r0 = Start Address
|
||||||
|
@ r1 = Length
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
ClearMem:
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
mov r2, #3 @ Round down to nearest word boundary
|
||||||
|
add r1, r1, r2 @ Shouldn't be needed
|
||||||
|
bics r1, r1, r2 @ Clear 2 LSB (and set Z)
|
||||||
|
bxeq lr @ Quit if copy size is 0
|
||||||
|
|
||||||
|
mov r2, #0
|
||||||
|
ClrLoop:
|
||||||
|
stmia r0!, {r2}
|
||||||
|
subs r1, r1, #4
|
||||||
|
bne ClrLoop
|
||||||
|
|
||||||
|
bx lr
|
||||||
906
plugin/sources/ArticBaseFunctions.cpp
Normal file
906
plugin/sources/ArticBaseFunctions.cpp
Normal file
@ -0,0 +1,906 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ArticFunctions.hpp"
|
||||||
|
#include "Main.hpp"
|
||||||
|
#include "CTRPluginFramework/CTRPluginFramework.hpp"
|
||||||
|
#include "CTRPluginFramework/Clock.hpp"
|
||||||
|
#include "nim_extheader.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "csvc.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
extern bool isControllerMode;
|
||||||
|
constexpr u32 INITIAL_SETUP_APP_VERSION = 0;
|
||||||
|
|
||||||
|
enum class HandleType {
|
||||||
|
FILE,
|
||||||
|
DIR,
|
||||||
|
ARCHIVE
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ArticBaseFunctions {
|
||||||
|
|
||||||
|
ExHeader_Info lastAppExheader;
|
||||||
|
std::map<u64, HandleType> openHandles;
|
||||||
|
CTRPluginFramework::Mutex amMutex;
|
||||||
|
CTRPluginFramework::Mutex cfgMutex;
|
||||||
|
|
||||||
|
void Process_GetTitleID(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* tid_buffer = mi.ReserveResultBuffer(0, sizeof(u64));
|
||||||
|
if (!tid_buffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s64 out;
|
||||||
|
svcGetProcessInfo(&out, CUR_PROCESS_HANDLE, 0x10001);
|
||||||
|
|
||||||
|
memcpy(tid_buffer->data, &out, sizeof(s64));
|
||||||
|
|
||||||
|
mi.FinishGood(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process_GetProductInfo(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* prod_code_buffer = mi.ReserveResultBuffer(0, sizeof(FS_ProductInfo));
|
||||||
|
if (!prod_code_buffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 pid;
|
||||||
|
Result res = svcGetProcessId(&pid, CUR_PROCESS_HANDLE);
|
||||||
|
if (R_SUCCEEDED(res)) res = FSUSER_GetProductInfo((FS_ProductInfo*)prod_code_buffer->data, pid);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
logger.Error("Process_GetProductInfo: 0x%08X", res);
|
||||||
|
mi.FinishInternalError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mi.FinishGood(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process_GetExheader(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* exheader_buf = mi.ReserveResultBuffer(0, sizeof(lastAppExheader));
|
||||||
|
if (!exheader_buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(exheader_buf->data, &lastAppExheader, exheader_buf->bufferSize);
|
||||||
|
|
||||||
|
mi.FinishGood(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process_ReadCode(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s32 offset, size;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(offset);
|
||||||
|
if (good) good = mi.GetParameterS32(size);
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
s64 out;
|
||||||
|
if (R_FAILED(svcGetProcessInfo(&out, CUR_PROCESS_HANDLE, 0x10005))) {
|
||||||
|
mi.FinishInternalError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
u8* start_addr = reinterpret_cast<u8*>(out);
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* code_buf = mi.ReserveResultBuffer(0, size);
|
||||||
|
if (!code_buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(code_buf->data, start_addr + offset, size);
|
||||||
|
|
||||||
|
mi.FinishGood(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _Process_ReadExefs(ArticProtocolServer::MethodInterface& mi, const char* section) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
// Set up FS_Path structures
|
||||||
|
u8 path[0xC] = {0};
|
||||||
|
u32* type = (u32*)path;
|
||||||
|
char* name = (char*)(path + sizeof(u32));
|
||||||
|
|
||||||
|
*type = 0x2; // ExeFS
|
||||||
|
strcpy(name, section); // Icon
|
||||||
|
|
||||||
|
FS_Path archPath = { PATH_EMPTY, 1, "" };
|
||||||
|
FS_Path filePath = { PATH_BINARY, sizeof(path), path };
|
||||||
|
|
||||||
|
// Open the RomFS file and mount it
|
||||||
|
Handle fd = 0;
|
||||||
|
Result rc = FSUSER_OpenFileDirectly(&fd, ARCHIVE_ROMFS, archPath, filePath, FS_OPEN_READ, 0);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
mi.FinishGood(rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 file_size;
|
||||||
|
rc = FSFILE_GetSize(fd, &file_size);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
FSFILE_Close(fd);
|
||||||
|
mi.FinishGood(rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* icon_buf = mi.ReserveResultBuffer(0, static_cast<size_t>(file_size));
|
||||||
|
if (!icon_buf) {
|
||||||
|
FSFILE_Close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 bytes_read;
|
||||||
|
rc = FSFILE_Read(fd, &bytes_read, 0, icon_buf->data, icon_buf->bufferSize);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
FSFILE_Close(fd);
|
||||||
|
mi.ResizeLastResultBuffer(icon_buf, 0);
|
||||||
|
mi.FinishGood(rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mi.ResizeLastResultBuffer(icon_buf, bytes_read);
|
||||||
|
FSFILE_Close(fd);
|
||||||
|
|
||||||
|
mi.FinishGood(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process_ReadIcon(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
_Process_ReadExefs(mi, "icon");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process_ReadBanner(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
_Process_ReadExefs(mi, "banner");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process_ReadLogo(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
_Process_ReadExefs(mi, "logo");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetFSPath(ArticProtocolServer::MethodInterface& mi, FS_Path& path) {
|
||||||
|
void* pathPtr; size_t pathSize;
|
||||||
|
|
||||||
|
if (!mi.GetParameterBuffer(pathPtr, pathSize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
path.type = reinterpret_cast<FS_Path*>(pathPtr)->type;
|
||||||
|
path.size = reinterpret_cast<FS_Path*>(pathPtr)->size;
|
||||||
|
if (pathSize < 8 || path.size != pathSize - 0x8) {
|
||||||
|
mi.FinishInternalError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.data = (u8*)pathPtr + 0x8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSUSER_OpenFileDirectly_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
s32 archiveID;
|
||||||
|
FS_Path archPath;
|
||||||
|
FS_Path filePath;
|
||||||
|
s32 openFlags;
|
||||||
|
s32 attributes;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(archiveID);
|
||||||
|
if (good) good = GetFSPath(mi, archPath);
|
||||||
|
if (good) good = GetFSPath(mi, filePath);
|
||||||
|
if (good) good = mi.GetParameterS32(openFlags);
|
||||||
|
if (good) good = mi.GetParameterS32(attributes);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
Handle out;
|
||||||
|
Result res = FSUSER_OpenFileDirectly(&out, (FS_ArchiveID)archiveID, archPath, filePath, openFlags, attributes);
|
||||||
|
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* handle_buf = mi.ReserveResultBuffer(0, sizeof(Handle));
|
||||||
|
if (!handle_buf) {
|
||||||
|
FSFILE_Close(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<Handle*>(handle_buf->data) = out;
|
||||||
|
openHandles[(u64)out] = HandleType::FILE;
|
||||||
|
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSUSER_OpenArchive_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
s32 archiveID;
|
||||||
|
FS_Path archPath;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(archiveID);
|
||||||
|
if (good) good = GetFSPath(mi, archPath);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
FS_Archive out;
|
||||||
|
Result res = FSUSER_OpenArchive(&out, (FS_ArchiveID)archiveID, archPath);
|
||||||
|
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* handle_buf = mi.ReserveResultBuffer(0, sizeof(FS_Archive));
|
||||||
|
if (!handle_buf) {
|
||||||
|
FSUSER_CloseArchive(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<FS_Archive*>(handle_buf->data) = out;
|
||||||
|
openHandles[(u64)out] = HandleType::ARCHIVE;
|
||||||
|
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSUSER_CloseArchive_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
FS_Archive archive;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS64(*reinterpret_cast<s64*>(&archive));
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
Result res = FSUSER_CloseArchive(archive);
|
||||||
|
openHandles.erase((u64)archive);
|
||||||
|
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSUSER_OpenFile_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
FS_Archive archive;
|
||||||
|
FS_Path filePath;
|
||||||
|
s32 openFlags;
|
||||||
|
s32 attributes;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS64(*reinterpret_cast<s64*>(&archive));
|
||||||
|
if (good) good = GetFSPath(mi, filePath);
|
||||||
|
if (good) good = mi.GetParameterS32(openFlags);
|
||||||
|
if (good) good = mi.GetParameterS32(attributes);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
Handle out;
|
||||||
|
Result res = FSUSER_OpenFile(&out, archive, filePath, openFlags, attributes);
|
||||||
|
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* handle_buf = mi.ReserveResultBuffer(0, sizeof(Handle));
|
||||||
|
if (!handle_buf) {
|
||||||
|
FSFILE_Close(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<Handle*>(handle_buf->data) = out;
|
||||||
|
|
||||||
|
// Citra always asks for the size after opening a file, provided it here.
|
||||||
|
u64 fileSize;
|
||||||
|
Result res2 = FSFILE_GetSize(out, &fileSize);
|
||||||
|
if (R_SUCCEEDED(res2)) {
|
||||||
|
ArticBaseCommon::Buffer* size_buf = mi.ReserveResultBuffer(1, sizeof(u64));
|
||||||
|
if (!size_buf) {
|
||||||
|
FSFILE_Close(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<u64*>(size_buf->data) = fileSize;
|
||||||
|
}
|
||||||
|
openHandles[(u64)out] = HandleType::FILE;
|
||||||
|
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSUSER_OpenDirectory_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
FS_Archive archive;
|
||||||
|
FS_Path dirPath;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS64(*reinterpret_cast<s64*>(&archive));
|
||||||
|
if (good) good = GetFSPath(mi, dirPath);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
Handle out;
|
||||||
|
Result res = FSUSER_OpenDirectory(&out, archive, dirPath);
|
||||||
|
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* handle_buf = mi.ReserveResultBuffer(0, sizeof(Handle));
|
||||||
|
if (!handle_buf) {
|
||||||
|
FSDIR_Close(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<Handle*>(handle_buf->data) = out;
|
||||||
|
openHandles[(u64)out] = HandleType::DIR;
|
||||||
|
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSFILE_Close_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s32 handle;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(handle);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
Result res = FSFILE_Close(handle);
|
||||||
|
openHandles.erase((u64)handle);
|
||||||
|
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSFILE_GetSize_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s32 handle;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(handle);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
u64 fileSize;
|
||||||
|
Result res = FSFILE_GetSize(handle, &fileSize);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* size_buf = mi.ReserveResultBuffer(0, sizeof(u64));
|
||||||
|
if (!size_buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<u64*>(size_buf->data) = fileSize;
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSFILE_GetAttributes_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s32 handle;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(handle);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
u32 attributes;
|
||||||
|
Result res = FSFILE_GetAttributes(handle, &attributes);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* size_buf = mi.ReserveResultBuffer(0, sizeof(u32));
|
||||||
|
if (!size_buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<u32*>(size_buf->data) = attributes;
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSFILE_Read_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s32 handle, size;
|
||||||
|
s64 offset;
|
||||||
|
u32 bytes_read;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(handle);
|
||||||
|
if (good) good = mi.GetParameterS64(offset);
|
||||||
|
if (good) good = mi.GetParameterS32(size);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
logger.Debug("Read o=0x%08X, l=0x%08X", (u32)offset, (u32)size);
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* read_buf = mi.ReserveResultBuffer(0, size);
|
||||||
|
if (!read_buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result res = FSFILE_Read(handle, &bytes_read, offset, read_buf->data, read_buf->bufferSize);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.ResizeLastResultBuffer(read_buf, 0);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mi.ResizeLastResultBuffer(read_buf, bytes_read);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSDIR_Read_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s32 handle;
|
||||||
|
s32 entryCount;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(handle);
|
||||||
|
if (good) good = mi.GetParameterS32(entryCount);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* read_dir_buf = mi.ReserveResultBuffer(0, entryCount * sizeof(FS_DirectoryEntry));
|
||||||
|
if (!read_dir_buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 entries_read;
|
||||||
|
Result res = FSDIR_Read(handle, &entries_read, entryCount, reinterpret_cast<FS_DirectoryEntry*>(read_dir_buf->data));
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.ResizeLastResultBuffer(read_dir_buf, 0);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mi.ResizeLastResultBuffer(read_dir_buf, entries_read * sizeof(FS_DirectoryEntry));
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSDIR_Close_(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s32 handle;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS32(handle);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
Result res = FSDIR_Close(handle);
|
||||||
|
openHandles.erase((u64)handle);
|
||||||
|
|
||||||
|
mi.FinishGood(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System_IsAzaharInitialSetup(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
if (good) mi.FinishInputParameters();
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* ret_buf = mi.ReserveResultBuffer(0, 4);
|
||||||
|
if (!ret_buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret_buf->data[0] = INITIAL_SETUP_APP_VERSION;
|
||||||
|
|
||||||
|
mi.FinishGood(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System_GetSystemFile(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
s8 type;
|
||||||
|
|
||||||
|
if (good) good = mi.GetParameterS8(type);
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
if (type < 0 || type > 3) {
|
||||||
|
mi.FinishGood(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecureInfo_A
|
||||||
|
if (type >= 0 && type <= 2) {
|
||||||
|
Handle fspxiHandle;
|
||||||
|
Result res = svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, &fspxiHandle, "PxiFS0");
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FSPXI_Archive archive;
|
||||||
|
res = FSPXI_OpenArchive(fspxiHandle, &archive, ARCHIVE_NAND_CTR_FS, fsMakePath(PATH_EMPTY, ""));
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
svcCloseHandle(fspxiHandle);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* files[] = {"/rw/sys/SecureInfo_", "/rw/sys/LocalFriendCodeSeed_", "/private/movable.sed"};
|
||||||
|
char file_name[0x20] = {0};
|
||||||
|
strcpy(file_name, files[type]);
|
||||||
|
char* end = file_name + strlen(files[type]);
|
||||||
|
|
||||||
|
if (type == 0 || type == 1) {
|
||||||
|
*end = 'A';
|
||||||
|
}
|
||||||
|
|
||||||
|
FSPXI_File file;
|
||||||
|
res = FSPXI_OpenFile(fspxiHandle, &file, archive, fsMakePath(PATH_ASCII, file_name), FS_OPEN_READ, 0);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
*end = 'B';
|
||||||
|
res = FSPXI_OpenFile(fspxiHandle, &file, archive, fsMakePath(PATH_ASCII, file_name), FS_OPEN_READ, 0);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
FSPXI_CloseArchive(fspxiHandle, archive);
|
||||||
|
svcCloseHandle(fspxiHandle);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 size = 0;
|
||||||
|
res = FSPXI_GetFileSize(fspxiHandle, file, &size);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
FSPXI_CloseFile(fspxiHandle, file);
|
||||||
|
FSPXI_CloseArchive(fspxiHandle, archive);
|
||||||
|
svcCloseHandle(fspxiHandle);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* ret_buf = mi.ReserveResultBuffer(0, (int)size);
|
||||||
|
if (!ret_buf) {
|
||||||
|
FSPXI_CloseFile(fspxiHandle, file);
|
||||||
|
FSPXI_CloseArchive(fspxiHandle, archive);
|
||||||
|
svcCloseHandle(fspxiHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 bytes_read = 0;
|
||||||
|
res = FSPXI_ReadFile(fspxiHandle, file, &bytes_read, 0, ret_buf->data, (u32)size);
|
||||||
|
FSPXI_CloseFile(fspxiHandle, file);
|
||||||
|
FSPXI_CloseArchive(fspxiHandle, archive);
|
||||||
|
svcCloseHandle(fspxiHandle);
|
||||||
|
mi.FinishGood(bytes_read != size ? -2 : res);
|
||||||
|
} else if (type == 3) {
|
||||||
|
Result res = amInit();
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 deviceID;
|
||||||
|
res = AM_GetDeviceId(&deviceID);
|
||||||
|
amExit();
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char filePath[0x50];
|
||||||
|
sprintf(filePath, "/luma/backups/%08lX/otp.bin", deviceID);
|
||||||
|
|
||||||
|
Handle file;
|
||||||
|
|
||||||
|
res = FSUSER_OpenFileDirectly(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filePath), FS_OPEN_READ, 0);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
logger.Error("Missing OTP backup on SD card, please update your luma version and/or remove the console battery.");
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 size = 0;
|
||||||
|
res = FSFILE_GetSize(file, &size);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
FSFILE_Close(file);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* ret_buf = mi.ReserveResultBuffer(0, (int)size);
|
||||||
|
if (!ret_buf) {
|
||||||
|
FSFILE_Close(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 bytes_read = 0;
|
||||||
|
res = FSFILE_Read(file, &bytes_read, 0, ret_buf->data, (u32)size);
|
||||||
|
FSFILE_Close(file);
|
||||||
|
mi.FinishGood(bytes_read != size ? -2 : res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 getle32(const u8* p)
|
||||||
|
{
|
||||||
|
return (p[0]<<0) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 lzss_get_decompressed_size(u8* compressed, u32 compressedsize)
|
||||||
|
{
|
||||||
|
u8* footer = compressed + compressedsize - 8;
|
||||||
|
|
||||||
|
u32 originalbottom = getle32(footer+4);
|
||||||
|
|
||||||
|
return originalbottom + compressedsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lzss_decompress(u8* compressed, u32 compressedsize, u8* decompressed, u32 decompressedsize)
|
||||||
|
{
|
||||||
|
u8* footer = compressed + compressedsize - 8;
|
||||||
|
u32 buffertopandbottom = getle32(footer+0);
|
||||||
|
//u32 originalbottom = getle32(footer+4);
|
||||||
|
u32 i, j;
|
||||||
|
u32 out = decompressedsize;
|
||||||
|
u32 index = compressedsize - ((buffertopandbottom>>24)&0xFF);
|
||||||
|
u32 segmentoffset;
|
||||||
|
u32 segmentsize;
|
||||||
|
u8 control;
|
||||||
|
u32 stopindex = compressedsize - (buffertopandbottom&0xFFFFFF);
|
||||||
|
|
||||||
|
memset(decompressed, 0, decompressedsize);
|
||||||
|
memcpy(decompressed, compressed, compressedsize);
|
||||||
|
|
||||||
|
|
||||||
|
while(index > stopindex)
|
||||||
|
{
|
||||||
|
control = compressed[--index];
|
||||||
|
|
||||||
|
|
||||||
|
for(i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
if (index <= stopindex)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (index <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (out <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (control & 0x80)
|
||||||
|
{
|
||||||
|
if (index < 2)
|
||||||
|
{
|
||||||
|
// fprintf(stderr, "Error, compression out of bounds\n");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
index -= 2;
|
||||||
|
|
||||||
|
segmentoffset = compressed[index] | (compressed[index+1]<<8);
|
||||||
|
segmentsize = ((segmentoffset >> 12)&15)+3;
|
||||||
|
segmentoffset &= 0x0FFF;
|
||||||
|
segmentoffset += 2;
|
||||||
|
|
||||||
|
|
||||||
|
if (out < segmentsize)
|
||||||
|
{
|
||||||
|
// fprintf(stderr, "Error, compression out of bounds\n");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j=0; j<segmentsize; j++)
|
||||||
|
{
|
||||||
|
u8 data;
|
||||||
|
|
||||||
|
if (out+segmentoffset >= decompressedsize)
|
||||||
|
{
|
||||||
|
// fprintf(stderr, "Error, compression out of bounds\n");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = decompressed[out+segmentoffset];
|
||||||
|
decompressed[--out] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (out < 1)
|
||||||
|
{
|
||||||
|
// fprintf(stderr, "Error, compression out of bounds\n");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
decompressed[--out] = compressed[--index];
|
||||||
|
}
|
||||||
|
|
||||||
|
control <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
clean:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void System_GetNIM(ArticProtocolServer::MethodInterface& mi) {
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
if (good) good = mi.FinishInputParameters();
|
||||||
|
|
||||||
|
if (!good) return;
|
||||||
|
|
||||||
|
Handle file;
|
||||||
|
u32 archive_path[4] = {0x00002C02, 0x00040130, MEDIATYPE_NAND, 0x0};
|
||||||
|
u32 file_path[5] = {0x0, 0x0, 0x2, 0x646F632E, 0x00000065};
|
||||||
|
FS_Path archive_path_bin = {PATH_BINARY, 0x10, archive_path};
|
||||||
|
FS_Path file_path_bin = {PATH_BINARY, 0x14, file_path};
|
||||||
|
Result res = FSUSER_OpenFileDirectly(&file, ARCHIVE_SAVEDATA_AND_CONTENT, archive_path_bin, file_path_bin, FS_OPEN_READ, 0);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 size = 0;
|
||||||
|
res = FSFILE_GetSize(file, &size);
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
FSFILE_Close(file);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* buffer = (u8*)malloc((size_t)size);
|
||||||
|
u32 bytes_read = 0;
|
||||||
|
res = FSFILE_Read(file, &bytes_read, 0, buffer, (u32)size);
|
||||||
|
FSFILE_Close(file);
|
||||||
|
if (R_FAILED(res) || bytes_read != size) {
|
||||||
|
if (bytes_read != size) res = -2;
|
||||||
|
free(buffer);
|
||||||
|
mi.FinishGood(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArticBaseCommon::Buffer* ret_buf = mi.ReserveResultBuffer(0, nim_extheader_bin_size);
|
||||||
|
if (!ret_buf) {
|
||||||
|
free(buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(ret_buf->data, nim_extheader_bin, nim_extheader_bin_size);
|
||||||
|
ret_buf = mi.ReserveResultBuffer(1, lzss_get_decompressed_size(buffer, (u32)size));
|
||||||
|
if (!ret_buf) {
|
||||||
|
free(buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lzss_decompress(buffer, (u32)size, (u8*)ret_buf->data, ret_buf->bufferSize);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
u64 checksum = 0;
|
||||||
|
u64* start = (u64*)(ret_buf->data), *end = (u64*)((uintptr_t)(ret_buf->data + ret_buf->bufferSize) & ~7);
|
||||||
|
while (start != end) checksum = (checksum + *start++) * 0x6500000065ULL;
|
||||||
|
if (checksum != 0x50F9D326AB2239E9ULL) {
|
||||||
|
logger.Error("Invalid NIM checksum. Please ensure your console is on the latest version");
|
||||||
|
mi.ResizeLastResultBuffer(ret_buf, 0);
|
||||||
|
mi.FinishGood(-3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mi.FinishGood(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N>
|
||||||
|
constexpr auto& METHOD_NAME(char const (&s)[N]) {
|
||||||
|
static_assert(N < sizeof(ArticBaseCommon::RequestPacket::method), "String exceeds 32 bytes!");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, void(*)(ArticProtocolServer::MethodInterface& mi)> functionHandlers = {
|
||||||
|
{METHOD_NAME("Process_GetTitleID"), Process_GetTitleID},
|
||||||
|
{METHOD_NAME("Process_GetProductInfo"), Process_GetProductInfo},
|
||||||
|
{METHOD_NAME("Process_GetExheader"), Process_GetExheader},
|
||||||
|
{METHOD_NAME("Process_ReadCode"), Process_ReadCode},
|
||||||
|
{METHOD_NAME("Process_ReadIcon"), Process_ReadIcon},
|
||||||
|
{METHOD_NAME("Process_ReadBanner"), Process_ReadBanner},
|
||||||
|
{METHOD_NAME("Process_ReadLogo"), Process_ReadLogo},
|
||||||
|
{METHOD_NAME("FSUSER_OpenFileDirectly"), FSUSER_OpenFileDirectly_},
|
||||||
|
{METHOD_NAME("FSUSER_OpenArchive"), FSUSER_OpenArchive_},
|
||||||
|
{METHOD_NAME("FSUSER_CloseArchive"), FSUSER_CloseArchive_},
|
||||||
|
{METHOD_NAME("FSUSER_OpenFile"), FSUSER_OpenFile_},
|
||||||
|
{METHOD_NAME("FSUSER_OpenDirectory"), FSUSER_OpenDirectory_},
|
||||||
|
{METHOD_NAME("FSFILE_Close"), FSFILE_Close_},
|
||||||
|
{METHOD_NAME("FSFILE_GetAttributes"), FSFILE_GetAttributes_},
|
||||||
|
{METHOD_NAME("FSFILE_GetSize"), FSFILE_GetSize_},
|
||||||
|
{METHOD_NAME("FSFILE_Read"), FSFILE_Read_},
|
||||||
|
{METHOD_NAME("FSDIR_Read"), FSDIR_Read_},
|
||||||
|
{METHOD_NAME("FSDIR_Close"), FSDIR_Close_},
|
||||||
|
|
||||||
|
{METHOD_NAME("System_IsAzaharInitialSetup"), System_IsAzaharInitialSetup},
|
||||||
|
{METHOD_NAME("System_GetSystemFile"), System_GetSystemFile},
|
||||||
|
{METHOD_NAME("System_GetNIM"), System_GetNIM},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool obtainExheader() {
|
||||||
|
Result loaderInitCustom(void);
|
||||||
|
void loaderExitCustom(void);
|
||||||
|
Result LOADER_GetLastApplicationProgramInfo(ExHeader_Info* exheaderInfo);
|
||||||
|
|
||||||
|
|
||||||
|
Result res = loaderInitCustom();
|
||||||
|
if (R_SUCCEEDED(res)) res = LOADER_GetLastApplicationProgramInfo(&lastAppExheader);
|
||||||
|
loaderExitCustom();
|
||||||
|
|
||||||
|
if (R_FAILED(res)) {
|
||||||
|
logger.Error("Failed to get ExHeader. Luma3DS may be outdated.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool closeHandles() {
|
||||||
|
auto CloseHandle = [](u64 handle, HandleType type) {
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case HandleType::FILE:
|
||||||
|
logger.Debug("Call pending FSFILE_Close");
|
||||||
|
FSFILE_Close((Handle)handle);
|
||||||
|
break;
|
||||||
|
case HandleType::DIR:
|
||||||
|
logger.Debug("Call pending FSDIR_Close");
|
||||||
|
FSDIR_Close((Handle)handle);
|
||||||
|
break;
|
||||||
|
case HandleType::ARCHIVE:
|
||||||
|
logger.Debug("Call pending FSUSER_CloseArchive");
|
||||||
|
FSUSER_CloseArchive((FS_Archive)handle);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (auto it = openHandles.begin(); it != openHandles.end(); it++) {
|
||||||
|
CloseHandle(it->first, it->second);
|
||||||
|
}
|
||||||
|
openHandles.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool(*)()> setupFunctions {
|
||||||
|
obtainExheader,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<bool(*)()> destructFunctions {
|
||||||
|
closeHandles,
|
||||||
|
};
|
||||||
|
}
|
||||||
150
plugin/sources/BCLIM.cpp
Normal file
150
plugin/sources/BCLIM.cpp
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#include "BCLIM.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework {
|
||||||
|
|
||||||
|
static inline int ColorClamp(int Color)
|
||||||
|
{
|
||||||
|
if (Color > 255) Color = 255;
|
||||||
|
if (Color < 0) Color = 0;
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8 BCLIM::textureTileOrder[] =
|
||||||
|
{
|
||||||
|
0, 1, 4, 5,
|
||||||
|
2, 3, 6, 7,
|
||||||
|
|
||||||
|
8, 9, 12, 13,
|
||||||
|
10, 11, 14, 15
|
||||||
|
};
|
||||||
|
|
||||||
|
const u8 BCLIM::etc1Modifiers[][2] =
|
||||||
|
{
|
||||||
|
{ 2, 8 },
|
||||||
|
{ 5, 17 },
|
||||||
|
{ 9, 29 },
|
||||||
|
{ 13, 42 },
|
||||||
|
{ 18, 60 },
|
||||||
|
{ 24, 80 },
|
||||||
|
{ 33, 106 },
|
||||||
|
{ 47, 183 }
|
||||||
|
};
|
||||||
|
|
||||||
|
Color BCLIM::OpaqueBlendFunc(const Color& dst, const Color& src) {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color ReadPixel(void* fb, int posX, int posY) {
|
||||||
|
constexpr u32 _bytesPerPixel = 2;
|
||||||
|
constexpr u32 _rowSize = 240;
|
||||||
|
u32 offset = (_rowSize - 1 - posY + posX * _rowSize) * _bytesPerPixel;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u16 u;
|
||||||
|
u8 b[2];
|
||||||
|
} half;
|
||||||
|
half.u = *reinterpret_cast<u16 *>((u32)fb + offset);
|
||||||
|
Color c;
|
||||||
|
c.r = (half.u >> 8) & 0xF8;
|
||||||
|
c.g = (half.u >> 3) & 0xFC;
|
||||||
|
c.b = (half.u << 3) & 0xF8;
|
||||||
|
c.a = 255;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
static void WritePixel(void* fb, int posX, int posY, const Color& c) {
|
||||||
|
constexpr u32 _bytesPerPixel = 2;
|
||||||
|
constexpr u32 _rowSize = 240;
|
||||||
|
u32 offset = (_rowSize - 1 - posY + posX * _rowSize) * _bytesPerPixel;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u16 u;
|
||||||
|
u8 b[2];
|
||||||
|
} half;
|
||||||
|
half.u = (c.r & 0xF8) << 8;
|
||||||
|
half.u |= (c.g & 0xFC) << 3;
|
||||||
|
half.u |= (c.b & 0xF8) >> 3;
|
||||||
|
*reinterpret_cast<u16 *>((u32)fb + offset) = half.u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BCLIM::RenderInterfaceBackend(void* usrData, bool isRead, Color* c, int posX, int posY) {
|
||||||
|
if (isRead) {
|
||||||
|
*c = ReadPixel(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), posX, posY);
|
||||||
|
} else {
|
||||||
|
WritePixel(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), posX, posY, *c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FastContains(const Rect<int>& rect, Vector<int> point) {
|
||||||
|
return point.x >= rect.leftTop.x && point.x < (rect.leftTop.x + rect.size.x) &&
|
||||||
|
point.y >= rect.leftTop.y && point.y < (rect.leftTop.y + rect.size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BCLIM::Render(const Rect<int>& position, std::pair<void*, RenderBackend> backend, const Rect<int>& crop, const Rect<int>& limits, std::pair<bool, ColorBlendCallback> colorBlender) {
|
||||||
|
auto mappingScale = [](const Rect<int>& position, int x, int y, int w, int h) {
|
||||||
|
int posX = position.leftTop.x;
|
||||||
|
int posY = position.leftTop.y;
|
||||||
|
float progX = x/(float)w;
|
||||||
|
float progY = y/(float)h;
|
||||||
|
|
||||||
|
return Vector<int>(posX + position.size.x * progX, posY + position.size.y * progY);
|
||||||
|
};
|
||||||
|
auto mappingDirect = [](const Rect<int>& position, int x, int y, int w, int h) {
|
||||||
|
return Vector<int>(position.leftTop.x + x, position.leftTop.y + y);
|
||||||
|
};
|
||||||
|
Vector<int>(*mapping)(const Rect<int>& position, int x, int y, int w, int h);
|
||||||
|
Color current;
|
||||||
|
|
||||||
|
if (position.size.x == header->imag.width && position.size.y == header->imag.height)
|
||||||
|
mapping = mappingDirect;
|
||||||
|
else
|
||||||
|
mapping = mappingScale;
|
||||||
|
|
||||||
|
switch (header->imag.format) {
|
||||||
|
case TextureFormat::L8:
|
||||||
|
case TextureFormat::A8:
|
||||||
|
case TextureFormat::LA4:
|
||||||
|
case TextureFormat::LA8:
|
||||||
|
case TextureFormat::HILO8:
|
||||||
|
case TextureFormat::RGB8:
|
||||||
|
case TextureFormat::RGBA5551:
|
||||||
|
case TextureFormat::RGBA8:
|
||||||
|
case TextureFormat::ETC1:
|
||||||
|
case TextureFormat::L4:
|
||||||
|
case TextureFormat::A4:
|
||||||
|
case TextureFormat::RGBA4:
|
||||||
|
case TextureFormat::ETC1A4:
|
||||||
|
break;
|
||||||
|
case TextureFormat::RGB565:
|
||||||
|
{
|
||||||
|
int offs = 0;
|
||||||
|
Vector<int> prevPos(-1, -1);
|
||||||
|
for (int y = 0; y < header->imag.height; y+=8) {
|
||||||
|
for (int x = 0; x < header->imag.width; x+=8) {
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
int x2 = i % 8;
|
||||||
|
if (x + x2 >= crop.size.x || x + x2 >= header->imag.width) continue;
|
||||||
|
int y2 = i / 8;
|
||||||
|
if (y + y2 >= crop.size.y || y + y2 >= header->imag.height) continue;
|
||||||
|
auto drawPos = mapping(position, x + x2, y + y2, header->imag.width, header->imag.height);
|
||||||
|
if (!FastContains(limits, drawPos)) continue;
|
||||||
|
if (drawPos.x != prevPos.x || drawPos.y != prevPos.y) {
|
||||||
|
prevPos = drawPos;
|
||||||
|
int pos = textureTileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4);
|
||||||
|
u16 pixel = GetDataAt<u16>(offs + pos * 2);
|
||||||
|
u8 b = (u8)((pixel & 0x1F) << 3);
|
||||||
|
u8 g = (u8)((pixel & 0x7E0) >> 3);
|
||||||
|
u8 r = (u8)((pixel & 0xF800) >> 8);
|
||||||
|
if (colorBlender.first)
|
||||||
|
backend.second(backend.first, true, ¤t, drawPos.x, drawPos.y);
|
||||||
|
Color finalcolor = colorBlender.second(Color(r, g, b), current);
|
||||||
|
backend.second(backend.first, false, &finalcolor, drawPos.x, drawPos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offs += 64 * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
158
plugin/sources/CTRPluginFramework/Color.cpp
Normal file
158
plugin/sources/CTRPluginFramework/Color.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#include "CTRPluginFramework/Color.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
Color& Color::Fade(float fading)
|
||||||
|
{
|
||||||
|
if (fading > 1.0f || fading < -1.0f)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
if (fading > 0.0f)
|
||||||
|
{
|
||||||
|
float tint = 1.f - fading;
|
||||||
|
r = std::min((int)(255 - (255 - r) * tint), 255);
|
||||||
|
g = std::min((int)(255 - (255 - g) * tint), 255);
|
||||||
|
b = std::min((int)(255 - (255 - b) * tint), 255);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float shade = 1.f + fading;
|
||||||
|
|
||||||
|
r *= shade;
|
||||||
|
g *= shade;
|
||||||
|
b *= shade;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::Blend(const Color &color, BlendMode mode) const
|
||||||
|
{
|
||||||
|
// This is background, color is foreground
|
||||||
|
Color ret;
|
||||||
|
unsigned int _r;
|
||||||
|
unsigned int _g;
|
||||||
|
unsigned int _b;
|
||||||
|
unsigned int _a;
|
||||||
|
float forealpha = (float)color.a / 255.f;
|
||||||
|
float minusForeAlpha = 1.f - forealpha;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case BlendMode::Alpha:
|
||||||
|
_r = (forealpha * (float)color.r) + ((float)r * minusForeAlpha);
|
||||||
|
_g = (forealpha * (float)color.g) + ((float)g * minusForeAlpha);
|
||||||
|
_b = (forealpha * (float)color.b) + ((float)b * minusForeAlpha);
|
||||||
|
_a = color.a * a;
|
||||||
|
ret.r = std::min(_r, 255u);
|
||||||
|
ret.g = std::min(_g, 255u);
|
||||||
|
ret.b = std::min(_b, 255u);
|
||||||
|
ret.a = std::min(_a, 255u);
|
||||||
|
break;
|
||||||
|
case BlendMode::Add:
|
||||||
|
_r = a * r / 255 + 255 * color.r / 255;
|
||||||
|
_g = a * g / 255 + 255 * color.g / 255;
|
||||||
|
_b = a * b / 255 + 255 * color.b / 255;
|
||||||
|
_a = a + color.a;
|
||||||
|
ret.r = std::min(_r, 255u);
|
||||||
|
ret.g = std::min(_g, 255u);
|
||||||
|
ret.b = std::min(_b, 255u);
|
||||||
|
ret.a = std::min(_a, 255u);
|
||||||
|
break;
|
||||||
|
case BlendMode::Sub:
|
||||||
|
_r = a * r / 255 - 255 * color.r / 255;
|
||||||
|
_g = a * g / 255 - 255 * color.g / 255;
|
||||||
|
_b = a * b / 255 - 255 * color.b / 255;
|
||||||
|
_a = a - color.a;
|
||||||
|
ret.r = std::max(_r, 0u);
|
||||||
|
ret.g = std::max(_g, 0u);
|
||||||
|
ret.b = std::max(_b, 0u);
|
||||||
|
ret.a = std::max(_a, 0u);
|
||||||
|
break;
|
||||||
|
case BlendMode::Mul:
|
||||||
|
ret = *this * color;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = color;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator < (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r < right.r)
|
||||||
|
&& (b < right.b)
|
||||||
|
&& (g < right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator <= (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r <= right.r)
|
||||||
|
&& (b <= right.b)
|
||||||
|
&& (g <= right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator > (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r > right.r)
|
||||||
|
&& (b > right.b)
|
||||||
|
&& (g > right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Color::operator >= (const Color &right) const
|
||||||
|
{
|
||||||
|
return (( r >= right.r)
|
||||||
|
&& (b >= right.b)
|
||||||
|
&& (g >= right.g));
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::operator+(const Color& right) const
|
||||||
|
{
|
||||||
|
u8 _r(std::min(r + right.r, 255));
|
||||||
|
u8 _g(std::min(g + right.g, 255));
|
||||||
|
u8 _b(std::min(b + right.b, 255));
|
||||||
|
u8 _a(std::min(a + right.a, 255));
|
||||||
|
|
||||||
|
return (Color(_r, _g, _b, _a));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::operator-(const Color& right) const
|
||||||
|
{
|
||||||
|
u8 _r(std::max(r - right.r, 0));
|
||||||
|
u8 _g(std::max(g - right.g, 0));
|
||||||
|
u8 _b(std::max(b - right.b, 0));
|
||||||
|
u8 _a(std::max(a - right.a, 0));
|
||||||
|
|
||||||
|
return (Color(_r, _g, _b, _a));
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Color::operator*(const Color& right) const
|
||||||
|
{
|
||||||
|
u8 _r(r * right.r / 255);
|
||||||
|
u8 _g(g * right.g / 255);
|
||||||
|
u8 _b(b * right.b / 255);
|
||||||
|
u8 _a(a * right.a / 255);
|
||||||
|
|
||||||
|
return (Color(_r, _g, _b, _a));
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &Color::operator+=(const Color& right)
|
||||||
|
{
|
||||||
|
*this = *this + right;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &Color::operator-=(const Color& right)
|
||||||
|
{
|
||||||
|
*this = *this - right;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &Color::operator*=(const Color& right)
|
||||||
|
{
|
||||||
|
*this = *this * right;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
plugin/sources/CTRPluginFramework/Time.cpp
Normal file
26
plugin/sources/CTRPluginFramework/Time.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "3ds/types.h"
|
||||||
|
|
||||||
|
#include "CTRPluginFramework/Time.hpp"
|
||||||
|
|
||||||
|
namespace CTRPluginFramework
|
||||||
|
{
|
||||||
|
const Time Time::Zero;
|
||||||
|
|
||||||
|
float Time::AsSeconds(void) const
|
||||||
|
{
|
||||||
|
return (_ticks / (float)TicksPerSecond);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Time::AsMilliseconds(void) const
|
||||||
|
{
|
||||||
|
return static_cast<int>(_ticks / (TicksPerSecond / 1000.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s64 Time::AsMicroseconds(void) const
|
||||||
|
{
|
||||||
|
return static_cast<s64>(_ticks / (TicksPerSecond / 1000000.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
122
plugin/sources/csvc.s
Normal file
122
plugin/sources/csvc.s
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
@ This paricular file is licensed under the following terms:
|
||||||
|
|
||||||
|
@ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
|
||||||
|
@ for any damages arising from the use of this software.
|
||||||
|
@
|
||||||
|
@ Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
|
||||||
|
@ and redistribute it freely, subject to the following restrictions:
|
||||||
|
@
|
||||||
|
@ The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
||||||
|
@ If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||||
|
@
|
||||||
|
@ Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||||
|
@ This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
.arm
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
.macro SVC_BEGIN name
|
||||||
|
.section .text.\name, "ax", %progbits
|
||||||
|
.global \name
|
||||||
|
.type \name, %function
|
||||||
|
.align 2
|
||||||
|
.cfi_startproc
|
||||||
|
\name:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro SVC_END
|
||||||
|
.cfi_endproc
|
||||||
|
.endm
|
||||||
|
|
||||||
|
SVC_BEGIN svcCustomBackdoor
|
||||||
|
svc 0x80
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcConvertVAToPA
|
||||||
|
svc 0x90
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcFlushDataCacheRange
|
||||||
|
svc 0x91
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcFlushEntireDataCache
|
||||||
|
svc 0x92
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcInvalidateInstructionCacheRange
|
||||||
|
svc 0x93
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcInvalidateEntireInstructionCache
|
||||||
|
svc 0x94
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcMapProcessMemoryEx
|
||||||
|
str r4, [sp, #-4]!
|
||||||
|
ldr r4, [sp, #4]
|
||||||
|
svc 0xA0
|
||||||
|
ldr r4, [sp], #4
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcUnmapProcessMemoryEx
|
||||||
|
svc 0xA1
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlMemoryEx
|
||||||
|
push {r0, r4, r5}
|
||||||
|
ldr r0, [sp, #0xC]
|
||||||
|
ldr r4, [sp, #0xC+0x4]
|
||||||
|
ldr r5, [sp, #0xC+0x8]
|
||||||
|
svc 0xA2
|
||||||
|
pop {r2, r4, r5}
|
||||||
|
str r1, [r2]
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlMemoryUnsafe
|
||||||
|
str r4, [sp, #-4]!
|
||||||
|
ldr r4, [sp, #4]
|
||||||
|
svc 0xA3
|
||||||
|
ldr r4, [sp], #4
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcFreeMemory
|
||||||
|
svc 0xA3
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlService
|
||||||
|
svc 0xB0
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcCopyHandle
|
||||||
|
str r0, [sp, #-4]!
|
||||||
|
svc 0xB1
|
||||||
|
ldr r2, [sp], #4
|
||||||
|
str r1, [r2]
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcTranslateHandle
|
||||||
|
str r0, [sp, #-4]!
|
||||||
|
svc 0xB2
|
||||||
|
ldr r2, [sp], #4
|
||||||
|
str r1, [r2]
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcControlProcess
|
||||||
|
svc 0xB3
|
||||||
|
bx lr
|
||||||
|
SVC_END
|
||||||
41
plugin/sources/loaderCustom.cpp
Normal file
41
plugin/sources/loaderCustom.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "3ds.h"
|
||||||
|
|
||||||
|
namespace ArticBaseFunctions {
|
||||||
|
|
||||||
|
static Handle loaderHandleCustom;
|
||||||
|
static int loaderRefCountCustom;
|
||||||
|
Result loaderInitCustom(void)
|
||||||
|
{
|
||||||
|
Result res;
|
||||||
|
if (AtomicPostIncrement(&loaderRefCountCustom)) return 0;
|
||||||
|
res = srvGetServiceHandle(&loaderHandleCustom, "Loader");
|
||||||
|
if (R_FAILED(res)) AtomicDecrement(&loaderRefCountCustom);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loaderExitCustom(void)
|
||||||
|
{
|
||||||
|
if (AtomicDecrement(&loaderRefCountCustom)) return;
|
||||||
|
svcCloseHandle(loaderHandleCustom);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LOADER_GetLastApplicationProgramInfo(ExHeader_Info* exheaderInfo)
|
||||||
|
{
|
||||||
|
Result ret = 0;
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
u32 *staticbufs = getThreadStaticBuffers();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(0x102, 0, 0);
|
||||||
|
|
||||||
|
u32 staticbufscpy[2] = {staticbufs[0], staticbufs[1]};
|
||||||
|
staticbufs[0] = IPC_Desc_StaticBuffer(0x400, 0);
|
||||||
|
staticbufs[1] = (u32)exheaderInfo;
|
||||||
|
|
||||||
|
if(R_FAILED(ret = svcSendSyncRequest(loaderHandleCustom))) return ret;
|
||||||
|
|
||||||
|
staticbufs[0] = staticbufscpy[0];
|
||||||
|
staticbufs[1] = staticbufscpy[1];
|
||||||
|
|
||||||
|
return (Result)cmdbuf[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
2057
plugin/sources/logo.c
Normal file
2057
plugin/sources/logo.c
Normal file
File diff suppressed because it is too large
Load Diff
340
plugin/sources/main.cpp
Normal file
340
plugin/sources/main.cpp
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
#include "Main.hpp"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ArticProtocolServer.hpp"
|
||||||
|
#include "ArticFunctions.hpp"
|
||||||
|
#include "CTRPluginFramework/Clock.hpp"
|
||||||
|
#include "plgldr.h"
|
||||||
|
|
||||||
|
#include "BCLIM.hpp"
|
||||||
|
|
||||||
|
#include "logo.h"
|
||||||
|
|
||||||
|
#define SOC_ALIGN 0x1000
|
||||||
|
#define SOC_BUFFERSIZE 0x400000
|
||||||
|
|
||||||
|
Logger logger;
|
||||||
|
static bool should_run = true;
|
||||||
|
static int listen_fd = -1;
|
||||||
|
static int accept_fd = -1;
|
||||||
|
static ArticProtocolServer* articBase = nullptr;
|
||||||
|
static bool reloadBottomText = false;
|
||||||
|
|
||||||
|
int transferedBytes = 0;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "csvc.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisableSleep(void)
|
||||||
|
{
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
if (R_FAILED(mcuHwcInit()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (R_FAILED(MCUHWC_ReadRegister(0x18, ®, 1)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
reg |= 0x60; ///< Disable home btn & shell state events
|
||||||
|
MCUHWC_WriteRegister(0x18, ®, 1);
|
||||||
|
mcuHwcExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableSleep(void)
|
||||||
|
{
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
if (R_FAILED(mcuHwcInit()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (R_FAILED(MCUHWC_ReadRegister(0x18, ®, 1)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
reg &= ~0x60; ///< Enable home btn & shell state events
|
||||||
|
MCUHWC_WriteRegister(0x18, ®, 1);
|
||||||
|
mcuHwcExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start(void* arg) {
|
||||||
|
int res;
|
||||||
|
void* SOC_buffer = memalign(SOC_ALIGN, SOC_BUFFERSIZE);
|
||||||
|
if ((res = socInit((u32*)SOC_buffer, SOC_BUFFERSIZE)) != 0) {
|
||||||
|
free(SOC_buffer);
|
||||||
|
logger.Error("Server: Cannot initialize sockets");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (should_run) {
|
||||||
|
svcSleepThread(500000000);
|
||||||
|
struct sockaddr_in servaddr = {0};
|
||||||
|
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (listen_fd < 0) {
|
||||||
|
logger.Error("Server: Cannot create socket");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ArticProtocolServer::SetNonBlock(listen_fd, true)) {
|
||||||
|
logger.Error("Server:: Failed to set non-block");
|
||||||
|
close(listen_fd);
|
||||||
|
listen_fd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
servaddr.sin_family = AF_INET;
|
||||||
|
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
servaddr.sin_port = htons(SERVER_PORT);
|
||||||
|
res = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
|
||||||
|
if (res < 0) {
|
||||||
|
logger.Error("Server: Failed to bind() to port %d", SERVER_PORT);
|
||||||
|
close(listen_fd);
|
||||||
|
listen_fd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = listen(listen_fd, 1);
|
||||||
|
if (res < 0) {
|
||||||
|
if (should_run) {
|
||||||
|
logger.Error("Server: Failed to listen()");
|
||||||
|
}
|
||||||
|
close(listen_fd);
|
||||||
|
listen_fd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct in_addr host_id;
|
||||||
|
host_id.s_addr = gethostid();
|
||||||
|
logger.Info("Server: Listening on: %s:%d", inet_ntoa(host_id), SERVER_PORT);
|
||||||
|
|
||||||
|
struct sockaddr_in peeraddr = {0};
|
||||||
|
socklen_t peeraddr_len = sizeof(peeraddr);
|
||||||
|
bool error = false;
|
||||||
|
while (true) {
|
||||||
|
accept_fd = accept(listen_fd, (struct sockaddr *) &peeraddr, &peeraddr_len);
|
||||||
|
if (accept_fd < 0 || peeraddr_len == 0) {
|
||||||
|
if (errno == EWOULDBLOCK && should_run) {
|
||||||
|
svcSleepThread(10000000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (should_run) {
|
||||||
|
logger.Error("Server: Failed to accept()");
|
||||||
|
}
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (listen_fd >= 0) {
|
||||||
|
close(listen_fd);
|
||||||
|
listen_fd = -1;
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
logger.Info("Server: Connected: %s:%d", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
|
||||||
|
|
||||||
|
if (!ArticProtocolServer::SetNonBlock(accept_fd, true)) {
|
||||||
|
logger.Error("Server: Failed to set non-block");
|
||||||
|
shutdown(accept_fd, SHUT_RDWR);
|
||||||
|
close(accept_fd);
|
||||||
|
accept_fd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
articBase = new ArticProtocolServer(accept_fd);
|
||||||
|
articBase->Serve();
|
||||||
|
accept_fd = -1;
|
||||||
|
delete articBase;
|
||||||
|
articBase = nullptr;
|
||||||
|
logger.Info("Server: Disconnected");
|
||||||
|
|
||||||
|
for (auto it = ArticBaseFunctions::destructFunctions.begin(); it != ArticBaseFunctions::destructFunctions.end(); it++) {
|
||||||
|
(*it)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socExit();
|
||||||
|
free(SOC_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintConsole topScreenConsole, bottomScreenConsole;
|
||||||
|
|
||||||
|
void Main() {
|
||||||
|
logger.Start();
|
||||||
|
|
||||||
|
plgLdrInit();
|
||||||
|
bool prevPluginState = ((PluginHeader*)0x07000000)->config[0] != 0;
|
||||||
|
PLGLDR__SetPluginLoaderState(prevPluginState);
|
||||||
|
PLGLDR__ClearPluginLoadParameters();
|
||||||
|
plgLdrExit();
|
||||||
|
|
||||||
|
gspLcdInit();
|
||||||
|
|
||||||
|
gfxInitDefault();
|
||||||
|
consoleInit(GFX_TOP, &topScreenConsole);
|
||||||
|
consoleInit(GFX_BOTTOM, &bottomScreenConsole);
|
||||||
|
topScreenConsole.bg = 15; topScreenConsole.fg = 0;
|
||||||
|
bottomScreenConsole.bg = 15; bottomScreenConsole.fg = 0;
|
||||||
|
|
||||||
|
gfxSetDoubleBuffering(GFX_BOTTOM, false);
|
||||||
|
|
||||||
|
aptSetHomeAllowed(false);
|
||||||
|
|
||||||
|
consoleSelect(&bottomScreenConsole);
|
||||||
|
consoleClear();
|
||||||
|
consoleSelect(&topScreenConsole);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
{
|
||||||
|
CTRPluginFramework::BCLIM((void*)__data_logo_bin, __data_logo_bin_size).Render(CTRPluginFramework::Rect<int>((320 - 128) / 2, (240 - 128) / 2, 128, 128));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto print_bottom_info = []() {
|
||||||
|
logger.Raw(false, "\n Azahar Artic Setup v%d.%d.%d\n\n"
|
||||||
|
" - A: Enter sleep \n"
|
||||||
|
" - X: Show debug log \n"
|
||||||
|
" - Y: Restart server \n"
|
||||||
|
" - START: Exit \n"
|
||||||
|
, VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||||
|
};
|
||||||
|
|
||||||
|
print_bottom_info();
|
||||||
|
logger.Raw(true, "");
|
||||||
|
|
||||||
|
bool setupCorrect = true;
|
||||||
|
for (auto it = ArticBaseFunctions::setupFunctions.begin(); it != ArticBaseFunctions::setupFunctions.end(); it++) {
|
||||||
|
setupCorrect = (*it)() && setupCorrect;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread serverThread = nullptr;
|
||||||
|
if (!setupCorrect) {
|
||||||
|
logger.Error("Server: Setup failed");
|
||||||
|
} else {
|
||||||
|
s32 prio = 0;
|
||||||
|
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
|
||||||
|
serverThread = threadCreate(Start, nullptr, 0x1000, prio-1, -2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CTRPluginFramework::Clock clock;
|
||||||
|
bool sleeping = false;
|
||||||
|
|
||||||
|
DisableSleep();
|
||||||
|
|
||||||
|
while (aptMainLoop())
|
||||||
|
{
|
||||||
|
if (reloadBottomText) {
|
||||||
|
reloadBottomText = false;
|
||||||
|
|
||||||
|
print_bottom_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
hidScanInput();
|
||||||
|
|
||||||
|
u32 kDown = hidKeysDown();
|
||||||
|
u32 kHeld = hidKeysHeld();
|
||||||
|
|
||||||
|
if (((kDown & ~KEY_SELECT) != 0) && sleeping) {
|
||||||
|
sleeping = false;
|
||||||
|
GSPLCD_PowerOnBacklight(3);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((kDown & KEY_A) && !sleeping) {
|
||||||
|
sleeping = true;
|
||||||
|
GSPLCD_PowerOffBacklight(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((kDown & KEY_START)) {
|
||||||
|
logger.Info("Server: Exiting");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((kDown & KEY_Y)) {
|
||||||
|
if (articBase) {
|
||||||
|
logger.Info("Server: Restarting");
|
||||||
|
articBase->QueryStop();
|
||||||
|
} else {
|
||||||
|
logger.Debug("Server: Not started yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((kDown & KEY_X)) {
|
||||||
|
if (logger.debug_enable) {
|
||||||
|
logger.Info("Server: Debug log disabled");
|
||||||
|
logger.debug_enable = false;
|
||||||
|
} else {
|
||||||
|
logger.Info("Server: Debug log enabled");
|
||||||
|
logger.debug_enable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clock.HasTimePassed(CTRPluginFramework::Seconds(1)))
|
||||||
|
{
|
||||||
|
if (articBase) {
|
||||||
|
CTRPluginFramework::Time t = clock.GetElapsedTime();
|
||||||
|
float bytes = transferedBytes / t.AsSeconds();
|
||||||
|
transferedBytes = 0;
|
||||||
|
float value = (bytes >= 1000 * 1000) ? (bytes / 1000.f * 1000.f) : (bytes / 1000.f);
|
||||||
|
const char* unit = (bytes >= 1000 * 1000) ? "MB/s" : "KB/s";
|
||||||
|
logger.Traffic(" Traffic: %.02f %s \n", value, unit);
|
||||||
|
clock.Restart();
|
||||||
|
} else {
|
||||||
|
logger.Traffic(" \n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush and swap framebuffers
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
|
||||||
|
//Wait for VBlank
|
||||||
|
gspWaitForVBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
should_run = false;
|
||||||
|
if (listen_fd >= 0) {
|
||||||
|
close(listen_fd);
|
||||||
|
listen_fd = -1;
|
||||||
|
}
|
||||||
|
if (articBase) {
|
||||||
|
articBase->QueryStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverThread) {
|
||||||
|
threadJoin(serverThread, U64_MAX);
|
||||||
|
threadFree(serverThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnableSleep();
|
||||||
|
|
||||||
|
// Flush and swap framebuffers
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
|
||||||
|
//Wait for VBlank
|
||||||
|
gspWaitForVBlank();
|
||||||
|
|
||||||
|
gfxExit();
|
||||||
|
gspLcdExit();
|
||||||
|
logger.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
int main(int argc, char* argv[]);
|
||||||
|
}
|
||||||
|
// Entrypoint, game will starts when you exit this function
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
Main();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
347
plugin/sources/plgldr.c
Normal file
347
plugin/sources/plgldr.c
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
#include <3ds.h>
|
||||||
|
#include "plgldr.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "csvc.h"
|
||||||
|
|
||||||
|
static Handle plgLdrHandle;
|
||||||
|
static Handle plgLdrArbiter = 0;
|
||||||
|
static s32* plgEvent;
|
||||||
|
static s32* plgReply;
|
||||||
|
static int plgLdrRefCount;
|
||||||
|
static bool isN3DS;
|
||||||
|
static OnPlgLdrEventCb_t onPlgLdrEventCb = NULL;
|
||||||
|
|
||||||
|
static Result PLGLDR__GetArbiter(void)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(9, 0, 0);
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
plgLdrArbiter = cmdbuf[3];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result plgLdrInit(void)
|
||||||
|
{
|
||||||
|
s64 out = 0;
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 0x201);
|
||||||
|
isN3DS = out != 0;
|
||||||
|
if (AtomicPostIncrement(&plgLdrRefCount) == 0)
|
||||||
|
res = svcConnectToPort(&plgLdrHandle, "plg:ldr");
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(res))
|
||||||
|
{
|
||||||
|
u32 res2 = PLGLDR__GetArbiter();
|
||||||
|
if (R_SUCCEEDED(res2) || res2 == 0xE0E01BF4) { // Succeeded or not implemented (citra)
|
||||||
|
PluginHeader *header = (PluginHeader *)0x07000000;
|
||||||
|
|
||||||
|
plgEvent = header->plgldrEvent;
|
||||||
|
plgReply = header->plgldrReply;
|
||||||
|
} else
|
||||||
|
plgLdrExit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plgLdrExit();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plgLdrExit(void)
|
||||||
|
{
|
||||||
|
if (AtomicDecrement(&plgLdrRefCount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (plgLdrHandle)
|
||||||
|
svcCloseHandle(plgLdrHandle);
|
||||||
|
if (plgLdrArbiter)
|
||||||
|
svcCloseHandle(plgLdrArbiter);
|
||||||
|
plgLdrHandle = plgLdrArbiter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(2, 0, 0);
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
*isEnabled = cmdbuf[2];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__SetPluginLoaderState(bool enabled)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(3, 1, 0);
|
||||||
|
cmdbuf[1] = (u32)enabled;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(4, 2, 4);
|
||||||
|
cmdbuf[1] = (u32)parameters->noFlash | (((u32)parameters->pluginMemoryStrategy) << 8) | (((u32)parameters->persistent) << 16);
|
||||||
|
cmdbuf[2] = parameters->lowTitleId;
|
||||||
|
cmdbuf[3] = IPC_Desc_Buffer(256, IPC_BUFFER_R);
|
||||||
|
cmdbuf[4] = (u32)parameters->path;
|
||||||
|
cmdbuf[5] = IPC_Desc_Buffer(32 * sizeof(u32), IPC_BUFFER_R);
|
||||||
|
cmdbuf[6] = (u32)parameters->config;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
void Flash(u32 color);
|
||||||
|
Result PLGLDR__DisplayMenu(PluginMenu *menu)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 nbItems = menu->nbItems;
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(5, 1, 8);
|
||||||
|
cmdbuf[1] = nbItems;
|
||||||
|
cmdbuf[2] = IPC_Desc_Buffer(nbItems, IPC_BUFFER_RW);
|
||||||
|
cmdbuf[3] = (u32)menu->states;
|
||||||
|
cmdbuf[4] = IPC_Desc_Buffer(MAX_BUFFER, IPC_BUFFER_R);
|
||||||
|
cmdbuf[5] = (u32)menu->title;
|
||||||
|
cmdbuf[6] = IPC_Desc_Buffer(MAX_BUFFER * nbItems, IPC_BUFFER_R);
|
||||||
|
cmdbuf[7] = (u32)menu->items;
|
||||||
|
cmdbuf[8] = IPC_Desc_Buffer(MAX_BUFFER * nbItems, IPC_BUFFER_R);
|
||||||
|
cmdbuf[9] = (u32)menu->hints;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
else Flash(0xFF0000);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__DisplayMessage(const char *title, const char *body)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(6, 0, 4);
|
||||||
|
cmdbuf[1] = IPC_Desc_Buffer(strlen(title), IPC_BUFFER_R);
|
||||||
|
cmdbuf[2] = (u32)title;
|
||||||
|
cmdbuf[3] = IPC_Desc_Buffer(strlen(body), IPC_BUFFER_R);
|
||||||
|
cmdbuf[4] = (u32)body;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__DisplayErrMessage(const char *title, const char *body, u32 error)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(7, 1, 4);
|
||||||
|
cmdbuf[1] = error;
|
||||||
|
cmdbuf[2] = IPC_Desc_Buffer(strlen(title), IPC_BUFFER_R);
|
||||||
|
cmdbuf[3] = (u32)title;
|
||||||
|
cmdbuf[4] = IPC_Desc_Buffer(strlen(body), IPC_BUFFER_R);
|
||||||
|
cmdbuf[5] = (u32)body;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__GetVersion(u32 *version)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(8, 0, 0);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
if (cmdbuf[0] != IPC_MakeHeader(8, 2, 0))
|
||||||
|
return 0xD900182F;
|
||||||
|
|
||||||
|
res = cmdbuf[1];
|
||||||
|
if (version)
|
||||||
|
*version = cmdbuf[2];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__GetPluginPath(char *path)
|
||||||
|
{
|
||||||
|
if (path == NULL)
|
||||||
|
return MAKERESULT(28, 7, 254, 1014); ///< Usage, App, Invalid argument
|
||||||
|
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(10, 0, 2);
|
||||||
|
cmdbuf[1] = IPC_Desc_Buffer(255, IPC_BUFFER_RW);
|
||||||
|
cmdbuf[2] = (u32)path;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__SetRosalinaMenuBlock(bool shouldBlock)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(11, 1, 0);
|
||||||
|
cmdbuf[1] = (u32)shouldBlock;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__SetSwapSettings(const char* swapPath, void* encFunc, void* decFunc, void* args)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32* trueArgs;
|
||||||
|
u32* cmdbuf = getThreadCommandBuffer();
|
||||||
|
u32 buf[0x10] = { 0 };
|
||||||
|
|
||||||
|
const char* trueSwapPath;
|
||||||
|
|
||||||
|
if (swapPath) trueSwapPath = swapPath;
|
||||||
|
else trueSwapPath = "\0";
|
||||||
|
|
||||||
|
if (args) trueArgs = args;
|
||||||
|
else trueArgs = buf;
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(12, 2, 4);
|
||||||
|
cmdbuf[1] = (encFunc) ? (svcConvertVAToPA(encFunc, false) | (1 << 31)) : 0;
|
||||||
|
cmdbuf[2] = (decFunc) ? (svcConvertVAToPA(decFunc, false) | (1 << 31)) : 0;
|
||||||
|
cmdbuf[3] = IPC_Desc_Buffer(16 * sizeof(u32), IPC_BUFFER_R);
|
||||||
|
cmdbuf[4] = (u32)trueArgs;
|
||||||
|
cmdbuf[5] = IPC_Desc_Buffer(strlen(trueSwapPath) + 1, IPC_BUFFER_R);
|
||||||
|
cmdbuf[6] = (u32)trueSwapPath;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLGLDR__SetEventCallback(OnPlgLdrEventCb_t cb)
|
||||||
|
{
|
||||||
|
onPlgLdrEventCb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 __ldrex__(s32 *addr)
|
||||||
|
{
|
||||||
|
s32 val;
|
||||||
|
do
|
||||||
|
val = __ldrex(addr);
|
||||||
|
while (__strex(addr, val));
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __strex__(s32 *addr, s32 val)
|
||||||
|
{
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||||
|
s32 v;
|
||||||
|
do
|
||||||
|
v = __ldrex(addr);
|
||||||
|
while (__strex(addr, val));
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLGLDR__Status(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PLGLDR__FetchEvent(void)
|
||||||
|
{
|
||||||
|
s32 event = __ldrex__(plgEvent); // exclusive read necessary?
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLGLDR__Reply(s32 event)
|
||||||
|
{
|
||||||
|
__strex__(plgReply, PLG_OK);
|
||||||
|
|
||||||
|
if (event < PLG_ABOUT_TO_SWAP)
|
||||||
|
{
|
||||||
|
__strex__(plgEvent, PLG_OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
svcArbitrateAddress(plgLdrArbiter, (u32)plgReply, ARBITRATION_SIGNAL, 1, 0);
|
||||||
|
if (event == PLG_ABOUT_TO_SWAP)
|
||||||
|
{
|
||||||
|
__strex__(plgEvent, PLG_WAIT);
|
||||||
|
svcArbitrateAddress(plgLdrArbiter, (u32)plgEvent, ARBITRATION_WAIT_IF_LESS_THAN, PLG_OK, 0);
|
||||||
|
}
|
||||||
|
else if (event == PLG_ABOUT_TO_EXIT) {
|
||||||
|
svcExitThread();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__strex__(plgEvent, PLG_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PLGLDR__ClearPluginLoadParameters()
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
cmdbuf[0] = IPC_MakeHeader(14, 0, 0);
|
||||||
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
||||||
|
{
|
||||||
|
res = cmdbuf[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user