mirror of
https://github.com/Roberto-Nessy/OoT3D_Standalone_Free_Cam.git
synced 2025-10-05 15:52:43 +02:00
Initial Commit
This commit is contained in:
224
Makefile
Normal file
224
Makefile
Normal file
@@ -0,0 +1,224 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>DEVKITARM")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITARM)/3ds_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#
|
||||
# NO_SMDH: if set to anything, no SMDH file is generated.
|
||||
# ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional)
|
||||
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
|
||||
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
|
||||
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
|
||||
# ICON is the filename of the icon (.png), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.png
|
||||
# - icon.png
|
||||
# - <libctru folder>/default_icon.png
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := $(sort $(dir $(wildcard src/*/ src/)))
|
||||
DATA := data
|
||||
INCLUDES := include $(SOURCES)
|
||||
INCLUDES += assets
|
||||
#ROMFS := romfs
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
USA := USA
|
||||
EUR := EUR
|
||||
JP := JP
|
||||
REGION := USA
|
||||
|
||||
ifeq ($(USA), $(REGION))
|
||||
LINK_SCRIPT := oot.ld
|
||||
ASFLAGS += -D _USA_=1 -D _JP_=0 -D _EUR_=0
|
||||
endif
|
||||
ifeq ($(JP), $(REGION))
|
||||
LINK_SCRIPT := oot_j.ld
|
||||
ASFLAGS += -D _USA_=0 -D _JP_=1 -D _EUR_=0
|
||||
endif
|
||||
ifeq ($(EUR), $(REGION))
|
||||
LINK_SCRIPT := oot_e.ld
|
||||
ASFLAGS += -D _USA_=0 -D _JP_=0 -D _EUR_=1
|
||||
endif
|
||||
|
||||
VERFLAGS := -D USA=$(USA) -D JP=$(JP) -D EUR=$(EUR) -D REGION=$(REGION)
|
||||
|
||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp -mtp=soft -mfpu=vfpv2
|
||||
|
||||
CFLAGS := -g -Wall -mword-relocations -D DEBUG \
|
||||
-fomit-frame-pointer -ffunction-sections \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS $(VERFLAGS)
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
ASFLAGS += -g $(ARCH) $(VERFLAGS)
|
||||
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map) -T $(TOPDIR)/$(LINK_SCRIPT) -nostdlib $(VERFLAGS) -lgcc
|
||||
|
||||
LIBS := -lgcc
|
||||
|
||||
# Define version for the C code
|
||||
ifeq ($(REGION), $(USA))
|
||||
CFLAGS += -g -DVersion_USA
|
||||
endif
|
||||
ifeq ($(REGION), $(JP))
|
||||
CFLAGS += -g -DVersion_JP
|
||||
endif
|
||||
ifeq ($(REGION), $(EUR))
|
||||
CFLAGS += -g -DVersion_EUR
|
||||
endif
|
||||
|
||||
citra ?= 0
|
||||
ifneq ($(citra), 0)
|
||||
CFLAGS += -g -DCITRA
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(DEVKITARM) include/citro3d
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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)))
|
||||
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
|
||||
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \
|
||||
$(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)
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.png)
|
||||
ifneq (,$(findstring $(TARGET).png,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).png
|
||||
else
|
||||
ifneq (,$(findstring icon.png,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.png
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
@if ! python3 patch.py $(OUTPUT).elf; then \
|
||||
python patch.py $(OUTPUT).elf; \
|
||||
fi
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
$(OUTPUT).elf : $(OFILES) $(TOPDIR)/$(LINK_SCRIPT)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# rules for assembling GPU shaders
|
||||
#---------------------------------------------------------------------------------
|
||||
define shader-as
|
||||
$(eval CURBIN := $(patsubst %.shbin.o,%.shbin,$(notdir $@)))
|
||||
picasso -o $(CURBIN) $1
|
||||
bin2s $(CURBIN) | $(AS) -o $@
|
||||
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
|
||||
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
|
||||
echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
|
||||
endef
|
||||
|
||||
%.shbin.o : %.v.pica %.g.pica
|
||||
@echo $(notdir $^)
|
||||
@$(call shader-as,$^)
|
||||
|
||||
%.shbin.o : %.v.pica
|
||||
@echo $(notdir $<)
|
||||
@$(call shader-as,$<)
|
||||
|
||||
%.shbin.o : %.shlist
|
||||
@echo $(notdir $<)
|
||||
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file)))
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
BIN
Patch Files/EUR/3DS/code.ips
Normal file
BIN
Patch Files/EUR/3DS/code.ips
Normal file
Binary file not shown.
BIN
Patch Files/EUR/3DS/exheader.bin
Normal file
BIN
Patch Files/EUR/3DS/exheader.bin
Normal file
Binary file not shown.
BIN
Patch Files/EUR/Citra/code.ips
Normal file
BIN
Patch Files/EUR/Citra/code.ips
Normal file
Binary file not shown.
BIN
Patch Files/EUR/Citra/exheader.bin
Normal file
BIN
Patch Files/EUR/Citra/exheader.bin
Normal file
Binary file not shown.
BIN
Patch Files/JP/3DS/code.ips
Normal file
BIN
Patch Files/JP/3DS/code.ips
Normal file
Binary file not shown.
BIN
Patch Files/JP/3DS/exheader.bin
Normal file
BIN
Patch Files/JP/3DS/exheader.bin
Normal file
Binary file not shown.
BIN
Patch Files/JP/Citra/code.ips
Normal file
BIN
Patch Files/JP/Citra/code.ips
Normal file
Binary file not shown.
BIN
Patch Files/JP/Citra/exheader.bin
Normal file
BIN
Patch Files/JP/Citra/exheader.bin
Normal file
Binary file not shown.
BIN
Patch Files/USA/3DS/code.ips
Normal file
BIN
Patch Files/USA/3DS/code.ips
Normal file
Binary file not shown.
BIN
Patch Files/USA/3DS/exheader.bin
Normal file
BIN
Patch Files/USA/3DS/exheader.bin
Normal file
Binary file not shown.
BIN
Patch Files/USA/Citra/code.ips
Normal file
BIN
Patch Files/USA/Citra/code.ips
Normal file
Binary file not shown.
BIN
Patch Files/USA/Citra/exheader.bin
Normal file
BIN
Patch Files/USA/Citra/exheader.bin
Normal file
Binary file not shown.
36
README.md
Normal file
36
README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# OoT3D Free Cam
|
||||
This project allows new 3DS systems and Citra to control the camera in The Legend of Zelda: Ocarina of Time 3D with use of the c-stick, just like Majora's Mask 3D.
|
||||
|
||||
This project is still a WIP with 4 main features planned but not implemented:
|
||||
* Options to invert the axes
|
||||
* Sensitivity options
|
||||
* Better floor detection (sometimes you're kicked out of free cam when you shouldn't be with the current system)
|
||||
* JP version support (although the patch files are there they will currently crash as soon as you enter free cam)
|
||||
|
||||
# Shoutouts
|
||||
* Shoutouts to gamestabled for creating the practice patch and randomizer projects this shamelessly steals from
|
||||
* By extension, shoutouts to anyone gamestabled shouts out in those projects
|
||||
* Shoutouts to the OoT decomp team for creating an invaluable resource I referenced heavily while creating this
|
||||
* Shoutouts to Ura Yukimitsu for showing me how to get c-stick input working
|
||||
* Shoutouts to Hylian Freddy for creating the practice patch's memory viewer, another fantastic resource
|
||||
* Shoutouts to Kestron for motivating me to create the original free cam
|
||||
* Shoutouts to Skilar for getting me to make it a standalone project
|
||||
* Shoutouts to the whole OoT3DR dev team for being cool people and the community for keeping me motivated
|
||||
|
||||
# How to Use:
|
||||
* Find the patch files inside the "Patch Files" folder in this repository. They're divided by regional version of OoT3D (USA/EUR/JP) and by platform (3DS/Citra), so choose the correct ones.
|
||||
### 3DS
|
||||
* Install a recent build of Luma3DS, or use the one linked above. If you already have Luma3DS, you can upgrade by simply replacing "boot.firm" at the root of your SD card.
|
||||
* Place the patch files ("code.ips" and "exheader.bin") in the following folder (you may need to create the folder):
|
||||
|
||||
| Version | Location | Notes |
|
||||
|---|---|---|
|
||||
| USA | /luma/titles/0004000000033500 | |
|
||||
| JP | /luma/titles/0004000000033400 | WIP - will crash |
|
||||
| EUR | /luma/titles/0004000000033600 | |
|
||||
|
||||
* Hold Select while powering on the console to launch the Luma3DS menu. Turn on "Enable game patching". You should only need to do this once, unless if you disable game patching in the future.
|
||||
* It should work now! If not, you likely need to use a different version of Luma3DS (try the one linked above).
|
||||
|
||||
### Citra Emulator
|
||||
* Right-click on OoT3D from the game list and select "Open Mods Location". Place the patch files ("code.ips" and "exheader.bin") there.
|
32
include/3ds/allocator/mappable.h
Normal file
32
include/3ds/allocator/mappable.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file mappable.h
|
||||
* @brief Mappable memory allocator.
|
||||
* Edited from
|
||||
* https://github.com/devkitPro/libctru/blob/b18f04d88739283f6ffb55fe5ea77c73796cf61b/libctru/include/3ds/allocator/mappable.h
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
|
||||
#define OS_MAP_AREA_BEGIN 0x10000000 ///< Start of the mappable area in the virtual address space
|
||||
#define OS_MAP_AREA_END 0x14000000 ///< End of the mappable area in the virtual address space
|
||||
|
||||
/**
|
||||
* @brief Initializes the mappable allocator.
|
||||
* @param addrMin Minimum address.
|
||||
* @param addrMax Maxium address.
|
||||
*/
|
||||
void mappableInit(u32 addrMin, u32 addrMax);
|
||||
|
||||
/**
|
||||
* @brief Finds a mappable memory area.
|
||||
* @param size Size of the area to find.
|
||||
* @return The mappable area.
|
||||
*/
|
||||
void* mappableAlloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Frees a mappable area (stubbed).
|
||||
* @param mem Mappable area to free.
|
||||
*/
|
||||
void mappableFree(void* mem);
|
76
include/3ds/env.h
Normal file
76
include/3ds/env.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file env.h
|
||||
* @brief Homebrew environment information.
|
||||
* Source: https://github.com/devkitPro/libctru/blob/6360f4bdb1ca5f8131ffc92640c1dd16afb63083/libctru/include/3ds/env.h
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
/// System run-flags.
|
||||
enum {
|
||||
RUNFLAG_APTWORKAROUND = BIT(0), ///< Use APT workaround.
|
||||
RUNFLAG_APTREINIT = BIT(1), ///< Reinitialize APT.
|
||||
RUNFLAG_APTCHAINLOAD = BIT(2), ///< Chainload APT on return.
|
||||
};
|
||||
|
||||
#define __service_ptr NULL
|
||||
|
||||
/**
|
||||
* @brief Gets whether the application was launched from a homebrew environment.
|
||||
* @return Whether the application was launched from a homebrew environment.
|
||||
*/
|
||||
static inline bool envIsHomebrew(void) {
|
||||
return __service_ptr != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a handle from the environment handle list.
|
||||
* @param name Name of the handle.
|
||||
* @return The retrieved handle.
|
||||
*/
|
||||
Handle envGetHandle(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Gets the environment-recommended app ID to use with APT.
|
||||
* @return The APT app ID.
|
||||
*/
|
||||
static inline u32 envGetAptAppId(void) {
|
||||
extern u32 __apt_appid;
|
||||
return __apt_appid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the size of the application heap.
|
||||
* @return The application heap size.
|
||||
*/
|
||||
static inline u32 envGetHeapSize(void) {
|
||||
extern u32 __ctru_heap_size;
|
||||
return __ctru_heap_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the size of the linear heap.
|
||||
* @return The linear heap size.
|
||||
*/
|
||||
static inline u32 envGetLinearHeapSize(void) {
|
||||
extern u32 __ctru_linear_heap_size;
|
||||
return __ctru_linear_heap_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the environment argument list.
|
||||
* @return The argument list.
|
||||
*/
|
||||
static inline const char* envGetSystemArgList(void) {
|
||||
extern const char* __system_arglist;
|
||||
return __system_arglist;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the environment run flags.
|
||||
* @return The run flags.
|
||||
*/
|
||||
static inline u32 envGetSystemRunFlags(void) {
|
||||
extern u32 __system_runflags;
|
||||
return __system_runflags;
|
||||
}
|
111
include/3ds/ipc.h
Normal file
111
include/3ds/ipc.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file ipc.h
|
||||
* @brief Inter Process Communication helpers
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "3ds/types.h"
|
||||
|
||||
/// IPC buffer access rights.
|
||||
typedef enum {
|
||||
IPC_BUFFER_R = BIT(1), ///< Readable
|
||||
IPC_BUFFER_W = BIT(2), ///< Writable
|
||||
IPC_BUFFER_RW = IPC_BUFFER_R | IPC_BUFFER_W ///< Readable and Writable
|
||||
} IPC_BufferRights;
|
||||
|
||||
/**
|
||||
* @brief Creates a command header to be used for IPC
|
||||
* @param command_id ID of the command to create a header for.
|
||||
* @param normal_params Size of the normal parameters in words. Up to 63.
|
||||
* @param translate_params Size of the translate parameters in words. Up to 63.
|
||||
* @return The created IPC header.
|
||||
*
|
||||
* Normal parameters are sent directly to the process while the translate parameters might go through modifications and
|
||||
* checks by the kernel. The translate parameters are described by headers generated with the IPC_Desc_* functions.
|
||||
*
|
||||
* @note While #normal_params is equivalent to the number of normal parameters, #translate_params includes the size
|
||||
* occupied by the translate parameters headers.
|
||||
*/
|
||||
static inline u32 IPC_MakeHeader(u16 command_id, unsigned normal_params, unsigned translate_params) {
|
||||
return ((u32)command_id << 16) | (((u32)normal_params & 0x3F) << 6) | (((u32)translate_params & 0x3F) << 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a header to share handles
|
||||
* @param number The number of handles following this header. Max 64.
|
||||
* @return The created shared handles header.
|
||||
*
|
||||
* The #number next values are handles that will be shared between the two processes.
|
||||
*
|
||||
* @note Zero values will have no effect.
|
||||
*/
|
||||
static inline u32 IPC_Desc_SharedHandles(unsigned number) {
|
||||
return ((u32)(number - 1) << 26);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates the header to transfer handle ownership
|
||||
* @param number The number of handles following this header. Max 64.
|
||||
* @return The created handle transfer header.
|
||||
*
|
||||
* The #number next values are handles that will be duplicated and closed by the other process.
|
||||
*
|
||||
* @note Zero values will have no effect.
|
||||
*/
|
||||
static inline u32 IPC_Desc_MoveHandles(unsigned number) {
|
||||
return ((u32)(number - 1) << 26) | 0x10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the code to ask the kernel to fill the handle with the current process ID.
|
||||
* @return The code to request the current process ID.
|
||||
*
|
||||
* The next value is a placeholder that will be replaced by the current process ID by the kernel.
|
||||
*/
|
||||
static inline u32 IPC_Desc_CurProcessId(void) {
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
static inline DEPRECATED u32 IPC_Desc_CurProcessHandle(void) {
|
||||
return IPC_Desc_CurProcessId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a header describing a static buffer.
|
||||
* @param size Size of the buffer. Max ?0x03FFFF?.
|
||||
* @param buffer_id The Id of the buffer. Max 0xF.
|
||||
* @return The created static buffer header.
|
||||
*
|
||||
* The next value is a pointer to the buffer. It will be copied to TLS offset 0x180 + static_buffer_id*8.
|
||||
*/
|
||||
static inline u32 IPC_Desc_StaticBuffer(size_t size, unsigned buffer_id) {
|
||||
return (size << 14) | ((buffer_id & 0xF) << 10) | 0x2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a header describing a buffer to be sent over PXI.
|
||||
* @param size Size of the buffer. Max 0x00FFFFFF.
|
||||
* @param buffer_id The Id of the buffer. Max 0xF.
|
||||
* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have read-write access.
|
||||
* @return The created PXI buffer header.
|
||||
*
|
||||
* The next value is a phys-address of a table located in the BASE memregion.
|
||||
*/
|
||||
static inline u32 IPC_Desc_PXIBuffer(size_t size, unsigned buffer_id, bool is_read_only) {
|
||||
u8 type = 0x4;
|
||||
if (is_read_only)
|
||||
type = 0x6;
|
||||
return (size << 8) | ((buffer_id & 0xF) << 4) | type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a header describing a buffer from the main memory.
|
||||
* @param size Size of the buffer. Max 0x0FFFFFFF.
|
||||
* @param rights The rights of the buffer for the destination process.
|
||||
* @return The created buffer header.
|
||||
*
|
||||
* The next value is a pointer to the buffer.
|
||||
*/
|
||||
static inline u32 IPC_Desc_Buffer(size_t size, IPC_BufferRights rights) {
|
||||
return (size << 4) | 0x8 | rights;
|
||||
}
|
214
include/3ds/os.h
Normal file
214
include/3ds/os.h
Normal file
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @file os.h
|
||||
* @brief OS related stuff.
|
||||
*/
|
||||
#pragma once
|
||||
#include "svc.h"
|
||||
|
||||
#define SYSCLOCK_SOC (16756991)
|
||||
#define SYSCLOCK_ARM9 (SYSCLOCK_SOC * 8)
|
||||
#define SYSCLOCK_ARM11 (SYSCLOCK_ARM9 * 2)
|
||||
#define SYSCLOCK_ARM11_NEW (SYSCLOCK_ARM11 * 3)
|
||||
|
||||
#define CPU_TICKS_PER_MSEC (SYSCLOCK_ARM11 / 1000.0)
|
||||
#define CPU_TICKS_PER_USEC (SYSCLOCK_ARM11 / 1000000.0)
|
||||
|
||||
/// Packs a system version from its components.
|
||||
#define SYSTEM_VERSION(major, minor, revision) (((major) << 24) | ((minor) << 16) | ((revision) << 8))
|
||||
|
||||
/// Retrieves the major version from a packed system version.
|
||||
#define GET_VERSION_MAJOR(version) ((version) >> 24)
|
||||
|
||||
/// Retrieves the minor version from a packed system version.
|
||||
#define GET_VERSION_MINOR(version) (((version) >> 16) & 0xFF)
|
||||
|
||||
/// Retrieves the revision version from a packed system version.
|
||||
#define GET_VERSION_REVISION(version) (((version) >> 8) & 0xFF)
|
||||
|
||||
/// Memory regions.
|
||||
typedef enum {
|
||||
MEMREGION_ALL = 0, ///< All regions.
|
||||
MEMREGION_APPLICATION = 1, ///< APPLICATION memory.
|
||||
MEMREGION_SYSTEM = 2, ///< SYSTEM memory.
|
||||
MEMREGION_BASE = 3, ///< BASE memory.
|
||||
} MemRegion;
|
||||
|
||||
/// Tick counter.
|
||||
typedef struct {
|
||||
u64 elapsed; ///< Elapsed CPU ticks between measurements.
|
||||
u64 reference; ///< Point in time used as reference.
|
||||
} TickCounter;
|
||||
|
||||
/// OS_VersionBin. Format of the system version: "<major>.<minor>.<build>-<nupver><region>"
|
||||
typedef struct {
|
||||
u8 build;
|
||||
u8 minor;
|
||||
u8 mainver; //"major" in CVER, NUP version in NVer.
|
||||
u8 reserved_x3;
|
||||
char region; //"ASCII character for the system version region"
|
||||
u8 reserved_x5[0x3];
|
||||
} OS_VersionBin;
|
||||
|
||||
/**
|
||||
* @brief Converts an address from virtual (process) memory to physical memory.
|
||||
* @param vaddr Input virtual address.
|
||||
* @return The corresponding physical address.
|
||||
* It is sometimes required by services or when using the GPU command buffer.
|
||||
*/
|
||||
u32 osConvertVirtToPhys(const void* vaddr);
|
||||
|
||||
/**
|
||||
* @brief Converts 0x14* vmem to 0x30*.
|
||||
* @param vaddr Input virtual address.
|
||||
* @return The corresponding address in the 0x30* range, the input address if it's already within the new vmem, or 0 if
|
||||
* it's outside of both ranges.
|
||||
*/
|
||||
void* osConvertOldLINEARMemToNew(const void* vaddr);
|
||||
|
||||
/**
|
||||
* @brief Retrieves basic information about a service error.
|
||||
* @param error Error to retrieve information about.
|
||||
* @return A string containing a summary of an error.
|
||||
*
|
||||
* This can be used to get some details about an error returned by a service call.
|
||||
*/
|
||||
const char* osStrError(u32 error);
|
||||
|
||||
/**
|
||||
* @brief Gets the system's FIRM version.
|
||||
* @return The system's FIRM version.
|
||||
*
|
||||
* This can be used to compare system versions easily with @ref SYSTEM_VERSION.
|
||||
*/
|
||||
static inline u32 osGetFirmVersion(void) {
|
||||
return (*(vu32*)0x1FF80060) & ~0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the system's kernel version.
|
||||
* @return The system's kernel version.
|
||||
*
|
||||
* This can be used to compare system versions easily with @ref SYSTEM_VERSION.
|
||||
*
|
||||
* @code
|
||||
* if(osGetKernelVersion() > SYSTEM_VERSION(2,46,0)) printf("You are running 9.0 or higher\n");
|
||||
* @endcode
|
||||
*/
|
||||
static inline u32 osGetKernelVersion(void) {
|
||||
return (*(vu32*)0x1FF80000) & ~0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the size of the specified memory region.
|
||||
* @param region Memory region to check.
|
||||
* @return The size of the memory region, in bytes.
|
||||
*/
|
||||
static inline u32 osGetMemRegionSize(MemRegion region) {
|
||||
if (region == MEMREGION_ALL) {
|
||||
return osGetMemRegionSize(MEMREGION_APPLICATION) + osGetMemRegionSize(MEMREGION_SYSTEM) +
|
||||
osGetMemRegionSize(MEMREGION_BASE);
|
||||
} else {
|
||||
return *(vu32*)(0x1FF80040 + (region - 1) * 0x4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the number of used bytes within the specified memory region.
|
||||
* @param region Memory region to check.
|
||||
* @return The number of used bytes of memory.
|
||||
*/
|
||||
s64 osGetMemRegionUsed(MemRegion region);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of free bytes within the specified memory region.
|
||||
* @param region Memory region to check.
|
||||
* @return The number of free bytes of memory.
|
||||
*/
|
||||
static inline s64 osGetMemRegionFree(MemRegion region) {
|
||||
return (s64)osGetMemRegionSize(region) - osGetMemRegionUsed(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the current time.
|
||||
* @return The number of milliseconds since 1st Jan 1900 00:00.
|
||||
*/
|
||||
u64 osGetTime(void);
|
||||
|
||||
/**
|
||||
* @brief Starts a tick counter.
|
||||
* @param cnt The tick counter.
|
||||
*/
|
||||
static inline void osTickCounterStart(TickCounter* cnt) {
|
||||
cnt->reference = svcGetSystemTick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the elapsed time in a tick counter.
|
||||
* @param cnt The tick counter.
|
||||
*/
|
||||
static inline void osTickCounterUpdate(TickCounter* cnt) {
|
||||
u64 now = svcGetSystemTick();
|
||||
cnt->elapsed = now - cnt->reference;
|
||||
cnt->reference = now;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads the elapsed time in a tick counter.
|
||||
* @param cnt The tick counter.
|
||||
* @return The number of milliseconds elapsed.
|
||||
*/
|
||||
double osTickCounterRead(const TickCounter* cnt);
|
||||
|
||||
/**
|
||||
* @brief Gets the current Wifi signal strength.
|
||||
* @return The current Wifi signal strength.
|
||||
*
|
||||
* Valid values are 0-3:
|
||||
* - 0 means the singal strength is terrible or the 3DS is disconnected from
|
||||
* all networks.
|
||||
* - 1 means the signal strength is bad.
|
||||
* - 2 means the signal strength is decent.
|
||||
* - 3 means the signal strength is good.
|
||||
*
|
||||
* Values outside the range of 0-3 should never be returned.
|
||||
*
|
||||
* These values correspond with the number of wifi bars displayed by Home Menu.
|
||||
*/
|
||||
static inline u8 osGetWifiStrength(void) {
|
||||
return *(vu8*)0x1FF81066;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the state of the 3D slider.
|
||||
* @return The state of the 3D slider (0.0~1.0)
|
||||
*/
|
||||
static inline float osGet3DSliderState(void) {
|
||||
return *(volatile float*)0x1FF81080;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the New 3DS speedup.
|
||||
* @param enable Specifies whether to enable or disable the speedup.
|
||||
*/
|
||||
void osSetSpeedupEnable(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Gets the NAND system-version stored in NVer/CVer.
|
||||
* @param nver_versionbin Output OS_VersionBin structure for the data read from NVer.
|
||||
* @param cver_versionbin Output OS_VersionBin structure for the data read from CVer.
|
||||
* @return The result-code. This value can be positive if opening "romfs:/version.bin" fails with stdio, since errno
|
||||
* would be returned in that case. In some cases the error can be special negative values as well.
|
||||
*/
|
||||
Result osGetSystemVersionData(OS_VersionBin* nver_versionbin, OS_VersionBin* cver_versionbin);
|
||||
|
||||
/**
|
||||
* @brief This is a wrapper for osGetSystemVersionData.
|
||||
* @param nver_versionbin Optional output OS_VersionBin structure for the data read from NVer, can be NULL.
|
||||
* @param cver_versionbin Optional output OS_VersionBin structure for the data read from CVer, can be NULL.
|
||||
* @param sysverstr Output string where the printed system-version will be written, in the same format displayed by the
|
||||
* System Settings title.
|
||||
* @param sysverstr_maxsize Max size of the above string buffer, *including* NULL-terminator.
|
||||
* @return See osGetSystemVersionData.
|
||||
*/
|
||||
Result osGetSystemVersionDataString(OS_VersionBin* nver_versionbin, OS_VersionBin* cver_versionbin, char* sysverstr,
|
||||
u32 sysverstr_maxsize);
|
187
include/3ds/result.h
Normal file
187
include/3ds/result.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* @file result.h
|
||||
* @brief 3DS result code tools
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
/// Checks whether a result code indicates success.
|
||||
#define R_SUCCEEDED(res) ((res) >= 0)
|
||||
/// Checks whether a result code indicates failure.
|
||||
#define R_FAILED(res) ((res) < 0)
|
||||
/// Returns the level of a result code.
|
||||
#define R_LEVEL(res) (((res) >> 27) & 0x1F)
|
||||
/// Returns the summary of a result code.
|
||||
#define R_SUMMARY(res) (((res) >> 21) & 0x3F)
|
||||
/// Returns the module ID of a result code.
|
||||
#define R_MODULE(res) (((res) >> 10) & 0xFF)
|
||||
/// Returns the description of a result code.
|
||||
#define R_DESCRIPTION(res) ((res)&0x3FF)
|
||||
|
||||
/// Builds a result code from its constituent components.
|
||||
#define MAKERESULT(level, summary, module, description) \
|
||||
((((level)&0x1F) << 27) | (((summary)&0x3F) << 21) | (((module)&0xFF) << 10) | ((description)&0x3FF))
|
||||
|
||||
/// Result code level values.
|
||||
enum {
|
||||
// >= 0
|
||||
RL_SUCCESS = 0,
|
||||
RL_INFO = 1,
|
||||
|
||||
// < 0
|
||||
RL_FATAL = 0x1F,
|
||||
RL_RESET = RL_FATAL - 1,
|
||||
RL_REINITIALIZE = RL_FATAL - 2,
|
||||
RL_USAGE = RL_FATAL - 3,
|
||||
RL_PERMANENT = RL_FATAL - 4,
|
||||
RL_TEMPORARY = RL_FATAL - 5,
|
||||
RL_STATUS = RL_FATAL - 6,
|
||||
};
|
||||
|
||||
/// Result code summary values.
|
||||
enum {
|
||||
RS_SUCCESS = 0,
|
||||
RS_NOP = 1,
|
||||
RS_WOULDBLOCK = 2,
|
||||
RS_OUTOFRESOURCE = 3,
|
||||
RS_NOTFOUND = 4,
|
||||
RS_INVALIDSTATE = 5,
|
||||
RS_NOTSUPPORTED = 6,
|
||||
RS_INVALIDARG = 7,
|
||||
RS_WRONGARG = 8,
|
||||
RS_CANCELED = 9,
|
||||
RS_STATUSCHANGED = 10,
|
||||
RS_INTERNAL = 11,
|
||||
RS_INVALIDRESVAL = 63,
|
||||
};
|
||||
|
||||
/// Result code module values.
|
||||
enum {
|
||||
RM_COMMON = 0,
|
||||
RM_KERNEL = 1,
|
||||
RM_UTIL = 2,
|
||||
RM_FILE_SERVER = 3,
|
||||
RM_LOADER_SERVER = 4,
|
||||
RM_TCB = 5,
|
||||
RM_OS = 6,
|
||||
RM_DBG = 7,
|
||||
RM_DMNT = 8,
|
||||
RM_PDN = 9,
|
||||
RM_GSP = 10,
|
||||
RM_I2C = 11,
|
||||
RM_GPIO = 12,
|
||||
RM_DD = 13,
|
||||
RM_CODEC = 14,
|
||||
RM_SPI = 15,
|
||||
RM_PXI = 16,
|
||||
RM_FS = 17,
|
||||
RM_DI = 18,
|
||||
RM_HID = 19,
|
||||
RM_CAM = 20,
|
||||
RM_PI = 21,
|
||||
RM_PM = 22,
|
||||
RM_PM_LOW = 23,
|
||||
RM_FSI = 24,
|
||||
RM_SRV = 25,
|
||||
RM_NDM = 26,
|
||||
RM_NWM = 27,
|
||||
RM_SOC = 28,
|
||||
RM_LDR = 29,
|
||||
RM_ACC = 30,
|
||||
RM_ROMFS = 31,
|
||||
RM_AM = 32,
|
||||
RM_HIO = 33,
|
||||
RM_UPDATER = 34,
|
||||
RM_MIC = 35,
|
||||
RM_FND = 36,
|
||||
RM_MP = 37,
|
||||
RM_MPWL = 38,
|
||||
RM_AC = 39,
|
||||
RM_HTTP = 40,
|
||||
RM_DSP = 41,
|
||||
RM_SND = 42,
|
||||
RM_DLP = 43,
|
||||
RM_HIO_LOW = 44,
|
||||
RM_CSND = 45,
|
||||
RM_SSL = 46,
|
||||
RM_AM_LOW = 47,
|
||||
RM_NEX = 48,
|
||||
RM_FRIENDS = 49,
|
||||
RM_RDT = 50,
|
||||
RM_APPLET = 51,
|
||||
RM_NIM = 52,
|
||||
RM_PTM = 53,
|
||||
RM_MIDI = 54,
|
||||
RM_MC = 55,
|
||||
RM_SWC = 56,
|
||||
RM_FATFS = 57,
|
||||
RM_NGC = 58,
|
||||
RM_CARD = 59,
|
||||
RM_CARDNOR = 60,
|
||||
RM_SDMC = 61,
|
||||
RM_BOSS = 62,
|
||||
RM_DBM = 63,
|
||||
RM_CONFIG = 64,
|
||||
RM_PS = 65,
|
||||
RM_CEC = 66,
|
||||
RM_IR = 67,
|
||||
RM_UDS = 68,
|
||||
RM_PL = 69,
|
||||
RM_CUP = 70,
|
||||
RM_GYROSCOPE = 71,
|
||||
RM_MCU = 72,
|
||||
RM_NS = 73,
|
||||
RM_NEWS = 74,
|
||||
RM_RO = 75,
|
||||
RM_GD = 76,
|
||||
RM_CARD_SPI = 77,
|
||||
RM_EC = 78,
|
||||
RM_WEB_BROWSER = 79,
|
||||
RM_TEST = 80,
|
||||
RM_ENC = 81,
|
||||
RM_PIA = 82,
|
||||
RM_ACT = 83,
|
||||
RM_VCTL = 84,
|
||||
RM_OLV = 85,
|
||||
RM_NEIA = 86,
|
||||
RM_NPNS = 87,
|
||||
RM_AVD = 90,
|
||||
RM_L2B = 91,
|
||||
RM_MVD = 92,
|
||||
RM_NFC = 93,
|
||||
RM_UART = 94,
|
||||
RM_SPM = 95,
|
||||
RM_QTM = 96,
|
||||
RM_NFP = 97,
|
||||
RM_APPLICATION = 254,
|
||||
RM_INVALIDRESVAL = 255,
|
||||
};
|
||||
|
||||
/// Result code generic description values.
|
||||
enum {
|
||||
RD_SUCCESS = 0,
|
||||
RD_INVALID_RESULT_VALUE = 0x3FF,
|
||||
RD_TIMEOUT = RD_INVALID_RESULT_VALUE - 1,
|
||||
RD_OUT_OF_RANGE = RD_INVALID_RESULT_VALUE - 2,
|
||||
RD_ALREADY_EXISTS = RD_INVALID_RESULT_VALUE - 3,
|
||||
RD_CANCEL_REQUESTED = RD_INVALID_RESULT_VALUE - 4,
|
||||
RD_NOT_FOUND = RD_INVALID_RESULT_VALUE - 5,
|
||||
RD_ALREADY_INITIALIZED = RD_INVALID_RESULT_VALUE - 6,
|
||||
RD_NOT_INITIALIZED = RD_INVALID_RESULT_VALUE - 7,
|
||||
RD_INVALID_HANDLE = RD_INVALID_RESULT_VALUE - 8,
|
||||
RD_INVALID_POINTER = RD_INVALID_RESULT_VALUE - 9,
|
||||
RD_INVALID_ADDRESS = RD_INVALID_RESULT_VALUE - 10,
|
||||
RD_NOT_IMPLEMENTED = RD_INVALID_RESULT_VALUE - 11,
|
||||
RD_OUT_OF_MEMORY = RD_INVALID_RESULT_VALUE - 12,
|
||||
RD_MISALIGNED_SIZE = RD_INVALID_RESULT_VALUE - 13,
|
||||
RD_MISALIGNED_ADDRESS = RD_INVALID_RESULT_VALUE - 14,
|
||||
RD_BUSY = RD_INVALID_RESULT_VALUE - 15,
|
||||
RD_NO_DATA = RD_INVALID_RESULT_VALUE - 16,
|
||||
RD_INVALID_COMBINATION = RD_INVALID_RESULT_VALUE - 17,
|
||||
RD_INVALID_ENUM_VALUE = RD_INVALID_RESULT_VALUE - 18,
|
||||
RD_INVALID_SIZE = RD_INVALID_RESULT_VALUE - 19,
|
||||
RD_ALREADY_DONE = RD_INVALID_RESULT_VALUE - 20,
|
||||
RD_NOT_AUTHORIZED = RD_INVALID_RESULT_VALUE - 21,
|
||||
RD_TOO_LARGE = RD_INVALID_RESULT_VALUE - 22,
|
||||
RD_INVALID_SELECTION = RD_INVALID_RESULT_VALUE - 23,
|
||||
};
|
73
include/3ds/services/irrst.h
Normal file
73
include/3ds/services/irrst.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file irrst.h
|
||||
* @brief IRRST service.
|
||||
* Edited from
|
||||
* https://github.com/devkitPro/libctru/blob/b18f04d88739283f6ffb55fe5ea77c73796cf61b/libctru/include/3ds/services/irrst.h
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "3ds/types.h"
|
||||
|
||||
// See also: http://3dbrew.org/wiki/IR_Services http://3dbrew.org/wiki/IRRST_Shared_Memory
|
||||
|
||||
/// Circle Pad position.
|
||||
typedef struct {
|
||||
s16 dx; ///< Pad X
|
||||
s16 dy; ///< Pad Y
|
||||
} circlePosition;
|
||||
|
||||
/// IRRST's shared memory handle.
|
||||
extern Handle irrstMemHandle;
|
||||
|
||||
/// IRRST's shared memory.
|
||||
extern vu32* irrstSharedMem;
|
||||
|
||||
/// IRRST's state update event
|
||||
extern Handle irrstEvent;
|
||||
|
||||
/// Initializes IRRST.
|
||||
Result irrstInit(void);
|
||||
|
||||
/// Exits IRRST.
|
||||
void irrstExit(void);
|
||||
|
||||
/// Scans IRRST for input.
|
||||
void irrstScanInput(void);
|
||||
|
||||
/**
|
||||
* @brief Gets IRRST's held keys.
|
||||
* @return IRRST's held keys.
|
||||
*/
|
||||
u32 irrstKeysHeld(void);
|
||||
|
||||
/**
|
||||
* @brief Reads the current c-stick position.
|
||||
* @param pos Pointer to output the current c-stick position to.
|
||||
*/
|
||||
void irrstCstickRead(circlePosition* pos);
|
||||
|
||||
/**
|
||||
* @brief Waits for the IRRST input event to trigger.
|
||||
* @param nextEvent Whether to discard the current event and wait until the next event.
|
||||
*/
|
||||
void irrstWaitForEvent(bool nextEvent);
|
||||
|
||||
/// Macro for irrstCstickRead.
|
||||
#define hidCstickRead irrstCstickRead
|
||||
|
||||
/**
|
||||
* @brief Gets the shared memory and event handles for IRRST.
|
||||
* @param outMemHandle Pointer to write the shared memory handle to.
|
||||
* @param outEventHandle Pointer to write the event handle to.
|
||||
*/
|
||||
Result IRRST_GetHandles(Handle* outMemHandle, Handle* outEventHandle);
|
||||
|
||||
/**
|
||||
* @brief Initializes IRRST.
|
||||
* @param unk1 Unknown.
|
||||
* @param unk2 Unknown.
|
||||
*/
|
||||
Result IRRST_Initialize(u32 unk1, u8 unk2);
|
||||
|
||||
/// Shuts down IRRST.
|
||||
Result IRRST_Shutdown(void);
|
45
include/3ds/services/srvpm.h
Normal file
45
include/3ds/services/srvpm.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file srvpm.h
|
||||
* @brief srv:pm service.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../result.h"
|
||||
|
||||
/// Initializes srv:pm and the service API.
|
||||
Result srvPmInit(void);
|
||||
|
||||
/// Exits srv:pm and the service API.
|
||||
void srvPmExit(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the current srv:pm session handle.
|
||||
* @return The current srv:pm session handle.
|
||||
*/
|
||||
Handle* srvPmGetSessionHandle(void);
|
||||
|
||||
/**
|
||||
* @brief Publishes a notification to a process.
|
||||
* @param notificationId ID of the notification.
|
||||
* @param process Process to publish to.
|
||||
*/
|
||||
Result SRVPM_PublishToProcess(u32 notificationId, Handle process);
|
||||
|
||||
/**
|
||||
* @brief Publishes a notification to all processes.
|
||||
* @param notificationId ID of the notification.
|
||||
*/
|
||||
Result SRVPM_PublishToAll(u32 notificationId);
|
||||
|
||||
/**
|
||||
* @brief Registers a process with SRV.
|
||||
* @param pid ID of the process.
|
||||
* @param count Number of services within the service access control data.
|
||||
* @param serviceAccessControlList Service Access Control list.
|
||||
*/
|
||||
Result SRVPM_RegisterProcess(u32 pid, u32 count, const char (*serviceAccessControlList)[8]);
|
||||
|
||||
/**
|
||||
* @brief Unregisters a process with SRV.
|
||||
* @param pid ID of the process.
|
||||
*/
|
||||
Result SRVPM_UnregisterProcess(u32 pid);
|
147
include/3ds/srv.h
Normal file
147
include/3ds/srv.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @file srv.h
|
||||
* @brief Service API.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "3ds/types.h"
|
||||
|
||||
/// Initializes the service API.
|
||||
Result srvInit(void);
|
||||
|
||||
/// Exits the service API.
|
||||
void srvExit(void);
|
||||
|
||||
/**
|
||||
* @brief Makes srvGetServiceHandle non-blocking for the current thread (or blocking, the default), in case of
|
||||
* unavailable (full) requested services.
|
||||
* @param blocking Whether srvGetServiceHandle should be non-blocking.
|
||||
* srvGetServiceHandle will always block if the service hasn't been registered yet,
|
||||
* use srvIsServiceRegistered to check whether that is the case or not.
|
||||
*/
|
||||
// void srvSetBlockingPolicy(bool nonBlocking);
|
||||
|
||||
/**
|
||||
* @brief Gets the current service API session handle.
|
||||
* @return The current service API session handle.
|
||||
*/
|
||||
Handle* srvGetSessionHandle(void);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a service handle, retrieving from the environment handle list if possible.
|
||||
* @param out Pointer to write the handle to.
|
||||
* @param name Name of the service.
|
||||
* @return 0 if no error occured,
|
||||
* 0xD8E06406 if the caller has no right to access the service,
|
||||
* 0xD0401834 if the requested service port is full and srvGetServiceHandle is non-blocking (see @ref
|
||||
* srvSetBlockingPolicy).
|
||||
*/
|
||||
Result srvGetServiceHandle(Handle* out, const char* name);
|
||||
|
||||
/// Registers the current process as a client to the service API.
|
||||
Result srvRegisterClient(void);
|
||||
|
||||
/**
|
||||
* @brief Enables service notificatios, returning a notification semaphore.
|
||||
* @param semaphoreOut Pointer to output the notification semaphore to.
|
||||
*/
|
||||
Result srvEnableNotification(Handle* semaphoreOut);
|
||||
|
||||
/**
|
||||
* @brief Registers the current process as a service.
|
||||
* @param out Pointer to write the service handle to.
|
||||
* @param name Name of the service.
|
||||
* @param maxSessions Maximum number of sessions the service can handle.
|
||||
*/
|
||||
Result srvRegisterService(Handle* out, const char* name, int maxSessions);
|
||||
|
||||
/**
|
||||
* @brief Unregisters the current process as a service.
|
||||
* @param name Name of the service.
|
||||
*/
|
||||
Result srvUnregisterService(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a service handle.
|
||||
* @param out Pointer to output the handle to.
|
||||
* @param name Name of the service.
|
||||
* * @return 0 if no error occured,
|
||||
* 0xD8E06406 if the caller has no right to access the service,
|
||||
* 0xD0401834 if the requested service port is full and srvGetServiceHandle is non-blocking (see @ref
|
||||
* srvSetBlockingPolicy).
|
||||
*/
|
||||
Result srvGetServiceHandleDirect(Handle* out, const char* name);
|
||||
|
||||
/**
|
||||
* @brief Registers a port.
|
||||
* @param name Name of the port.
|
||||
* @param clientHandle Client handle of the port.
|
||||
*/
|
||||
Result srvRegisterPort(const char* name, Handle clientHandle);
|
||||
|
||||
/**
|
||||
* @brief Unregisters a port.
|
||||
* @param name Name of the port.
|
||||
*/
|
||||
Result srvUnregisterPort(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a port handle.
|
||||
* @param out Pointer to output the handle to.
|
||||
* @param name Name of the port.
|
||||
*/
|
||||
Result srvGetPort(Handle* out, const char* name);
|
||||
|
||||
/**
|
||||
* @brief Waits for a port to be registered.
|
||||
* @param name Name of the port to wait for registration.
|
||||
*/
|
||||
Result srvWaitForPortRegistered(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Subscribes to a notification.
|
||||
* @param notificationId ID of the notification.
|
||||
*/
|
||||
Result srvSubscribe(u32 notificationId);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribes from a notification.
|
||||
* @param notificationId ID of the notification.
|
||||
*/
|
||||
Result srvUnsubscribe(u32 notificationId);
|
||||
|
||||
/**
|
||||
* @brief Receives a notification.
|
||||
* @param notificationIdOut Pointer to output the ID of the received notification to.
|
||||
*/
|
||||
Result srvReceiveNotification(u32* notificationIdOut);
|
||||
|
||||
/**
|
||||
* @brief Publishes a notification to subscribers.
|
||||
* @param notificationId ID of the notification.
|
||||
* @param flags Flags to publish with. (bit 0 = only fire if not fired, bit 1 = do not report an error if there are more
|
||||
* than 16 pending notifications)
|
||||
*/
|
||||
Result srvPublishToSubscriber(u32 notificationId, u32 flags);
|
||||
|
||||
/**
|
||||
* @brief Publishes a notification to subscribers and retrieves a list of all processes that were notified.
|
||||
* @param processIdCountOut Pointer to output the number of process IDs to.
|
||||
* @param processIdsOut Pointer to output the process IDs to. Should have size "60 * sizeof(u32)".
|
||||
* @param notificationId ID of the notification.
|
||||
*/
|
||||
Result srvPublishAndGetSubscriber(u32* processIdCountOut, u32* processIdsOut, u32 notificationId);
|
||||
|
||||
/**
|
||||
* @brief Checks whether a service is registered.
|
||||
* @param registeredOut Pointer to output the registration status to.
|
||||
* @param name Name of the service to check.
|
||||
*/
|
||||
Result srvIsServiceRegistered(bool* registeredOut, const char* name);
|
||||
|
||||
/**
|
||||
* @brief Checks whether a port is registered.
|
||||
* @param registeredOut Pointer to output the registration status to.
|
||||
* @param name Name of the port to check.
|
||||
*/
|
||||
Result srvIsPortRegistered(bool* registeredOut, const char* name);
|
1212
include/3ds/svc.h
Normal file
1212
include/3ds/svc.h
Normal file
File diff suppressed because it is too large
Load Diff
233
include/3ds/synchronization.h
Normal file
233
include/3ds/synchronization.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/**
|
||||
* @file synchronization.h
|
||||
* @brief Provides synchronization locks.
|
||||
*/
|
||||
#pragma once
|
||||
#include "3ds/sys/lock.h"
|
||||
#include "svc.h"
|
||||
|
||||
/// A light lock.
|
||||
typedef _LOCK_T LightLock;
|
||||
|
||||
/// A recursive lock.
|
||||
typedef _LOCK_RECURSIVE_T RecursiveLock;
|
||||
|
||||
/// A light event.
|
||||
typedef struct {
|
||||
s32 state; ///< State of the event: -2=cleared sticky, -1=cleared oneshot, 0=signaled oneshot, 1=signaled sticky
|
||||
LightLock lock; ///< Lock used for sticky timer operation
|
||||
} LightEvent;
|
||||
|
||||
/// A light semaphore.
|
||||
typedef struct {
|
||||
s32 current_count; ///< The current release count of the semaphore
|
||||
s16 num_threads_acq; ///< Number of threads concurrently acquiring the semaphore
|
||||
s16 max_count; ///< The maximum release count of the semaphore
|
||||
} LightSemaphore;
|
||||
|
||||
/// Performs a Data Synchronization Barrier operation.
|
||||
static inline void __dsb(void) {
|
||||
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" ::[val] "r"(0) : "memory");
|
||||
}
|
||||
|
||||
/// Performs a clrex operation.
|
||||
static inline void __clrex(void) {
|
||||
__asm__ __volatile__("clrex" ::: "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a ldrex operation.
|
||||
* @param addr Address to perform the operation on.
|
||||
* @return The resulting value.
|
||||
*/
|
||||
static inline s32 __ldrex(s32* addr) {
|
||||
s32 val;
|
||||
__asm__ __volatile__("ldrex %[val], %[addr]" : [val] "=r"(val) : [addr] "Q"(*addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a strex operation.
|
||||
* @param addr Address to perform the operation on.
|
||||
* @param val Value to store.
|
||||
* @return Whether the operation was successful.
|
||||
*/
|
||||
static inline bool __strex(s32* addr, s32 val) {
|
||||
bool res;
|
||||
__asm__ __volatile__("strex %[res], %[val], %[addr]" : [res] "=&r"(res) : [val] "r"(val), [addr] "Q"(*addr));
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a ldrexh operation.
|
||||
* @param addr Address to perform the operation on.
|
||||
* @return The resulting value.
|
||||
*/
|
||||
static inline u16 __ldrexh(u16* addr) {
|
||||
u16 val;
|
||||
__asm__ __volatile__("ldrexh %[val], %[addr]" : [val] "=r"(val) : [addr] "Q"(*addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a strexh operation.
|
||||
* @param addr Address to perform the operation on.
|
||||
* @param val Value to store.
|
||||
* @return Whether the operation was successful.
|
||||
*/
|
||||
static inline bool __strexh(u16* addr, u16 val) {
|
||||
bool res;
|
||||
__asm__ __volatile__("strexh %[res], %[val], %[addr]" : [res] "=&r"(res) : [val] "r"(val), [addr] "Q"(*addr));
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a ldrexb operation.
|
||||
* @param addr Address to perform the operation on.
|
||||
* @return The resulting value.
|
||||
*/
|
||||
static inline u8 __ldrexb(u8* addr) {
|
||||
u8 val;
|
||||
__asm__ __volatile__("ldrexb %[val], %[addr]" : [val] "=r"(val) : [addr] "Q"(*addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a strexb operation.
|
||||
* @param addr Address to perform the operation on.
|
||||
* @param val Value to store.
|
||||
* @return Whether the operation was successful.
|
||||
*/
|
||||
static inline bool __strexb(u8* addr, u8 val) {
|
||||
bool res;
|
||||
__asm__ __volatile__("strexb %[res], %[val], %[addr]" : [res] "=&r"(res) : [val] "r"(val), [addr] "Q"(*addr));
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Performs an atomic pre-increment operation.
|
||||
#define AtomicIncrement(ptr) __atomic_add_fetch((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
|
||||
/// Performs an atomic pre-decrement operation.
|
||||
#define AtomicDecrement(ptr) __atomic_sub_fetch((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
|
||||
/// Performs an atomic post-increment operation.
|
||||
#define AtomicPostIncrement(ptr) __atomic_fetch_add((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
|
||||
/// Performs an atomic post-decrement operation.
|
||||
#define AtomicPostDecrement(ptr) __atomic_fetch_sub((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
|
||||
/// Performs an atomic swap operation.
|
||||
#define AtomicSwap(ptr, value) __atomic_exchange_n((u32*)(ptr), (value), __ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* @brief Retrieves the synchronization subsystem's address arbiter handle.
|
||||
* @return The synchronization subsystem's address arbiter handle.
|
||||
*/
|
||||
Handle __sync_get_arbiter(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes a light lock.
|
||||
* @param lock Pointer to the lock.
|
||||
*/
|
||||
void LightLock_Init(LightLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Locks a light lock.
|
||||
* @param lock Pointer to the lock.
|
||||
*/
|
||||
void LightLock_Lock(LightLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Attempts to lock a light lock.
|
||||
* @param lock Pointer to the lock.
|
||||
* @return Zero on success, non-zero on failure.
|
||||
*/
|
||||
int LightLock_TryLock(LightLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Unlocks a light lock.
|
||||
* @param lock Pointer to the lock.
|
||||
*/
|
||||
void LightLock_Unlock(LightLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Initializes a recursive lock.
|
||||
* @param lock Pointer to the lock.
|
||||
*/
|
||||
void RecursiveLock_Init(RecursiveLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Locks a recursive lock.
|
||||
* @param lock Pointer to the lock.
|
||||
*/
|
||||
void RecursiveLock_Lock(RecursiveLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Attempts to lock a recursive lock.
|
||||
* @param lock Pointer to the lock.
|
||||
* @return Zero on success, non-zero on failure.
|
||||
*/
|
||||
int RecursiveLock_TryLock(RecursiveLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Unlocks a recursive lock.
|
||||
* @param lock Pointer to the lock.
|
||||
*/
|
||||
void RecursiveLock_Unlock(RecursiveLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Initializes a light event.
|
||||
* @param event Pointer to the event.
|
||||
* @param reset_type Type of reset the event uses (RESET_ONESHOT/RESET_STICKY).
|
||||
*/
|
||||
void LightEvent_Init(LightEvent* event, ResetType reset_type);
|
||||
|
||||
/**
|
||||
* @brief Clears a light event.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Clear(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Wakes up threads waiting on a sticky light event without signaling it. If the event had been signaled before,
|
||||
* it is cleared instead.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Pulse(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Signals a light event, waking up threads waiting on it.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Signal(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Attempts to wait on a light event.
|
||||
* @param event Pointer to the event.
|
||||
* @return Non-zero if the event was signaled, zero otherwise.
|
||||
*/
|
||||
int LightEvent_TryWait(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Waits on a light event.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Wait(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Initializes a light semaphore.
|
||||
* @param event Pointer to the semaphore.
|
||||
* @param max_count Initial count of the semaphore.
|
||||
* @param max_count Maximum count of the semaphore.
|
||||
*/
|
||||
void LightSemaphore_Init(LightSemaphore* semaphore, s16 initial_count, s16 max_count);
|
||||
|
||||
/**
|
||||
* @brief Acquires a light semaphore.
|
||||
* @param semaphore Pointer to the semaphore.
|
||||
* @param count Acquire count
|
||||
*/
|
||||
void LightSemaphore_Acquire(LightSemaphore* semaphore, s32 count);
|
||||
|
||||
/**
|
||||
* @brief Releases a light semaphore.
|
||||
* @param semaphore Pointer to the semaphore.
|
||||
* @param count Release count
|
||||
*/
|
||||
void LightSemaphore_Release(LightSemaphore* semaphore, s32 count);
|
54
include/3ds/sys/lock.h
Normal file
54
include/3ds/sys/lock.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef __SYS_LOCK_H__
|
||||
#define __SYS_LOCK_H__
|
||||
|
||||
// #include <_ansi.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int32_t _LOCK_T;
|
||||
|
||||
struct __lock_t {
|
||||
_LOCK_T lock;
|
||||
uint32_t thread_tag;
|
||||
uint32_t counter;
|
||||
};
|
||||
|
||||
typedef struct __lock_t _LOCK_RECURSIVE_T;
|
||||
|
||||
extern void __libc_lock_init(_LOCK_T* lock);
|
||||
extern void __libc_lock_init_recursive(_LOCK_RECURSIVE_T* lock);
|
||||
extern void __libc_lock_close(_LOCK_T* lock);
|
||||
extern void __libc_lock_close_recursive(_LOCK_RECURSIVE_T* lock);
|
||||
extern void __libc_lock_acquire(_LOCK_T* lock);
|
||||
extern void __libc_lock_acquire_recursive(_LOCK_RECURSIVE_T* lock);
|
||||
extern void __libc_lock_release(_LOCK_T* lock);
|
||||
extern void __libc_lock_release_recursive(_LOCK_RECURSIVE_T* lock);
|
||||
|
||||
/* Returns 0 for success and non-zero for failure */
|
||||
extern int __libc_lock_try_acquire(_LOCK_T* lock);
|
||||
extern int __libc_lock_try_acquire_recursive(_LOCK_RECURSIVE_T* lock);
|
||||
|
||||
#define __LOCK_INIT(CLASS, NAME) CLASS _LOCK_T NAME = 1;
|
||||
|
||||
#define __LOCK_INIT_RECURSIVE(CLASS, NAME) CLASS _LOCK_RECURSIVE_T NAME = { 1, 0, 0 };
|
||||
|
||||
#define __lock_init(NAME) __libc_lock_init(&(NAME))
|
||||
|
||||
#define __lock_init_recursive(NAME) __libc_lock_init_recursive(&(NAME))
|
||||
|
||||
#define __lock_close(NAME) __libc_lock_close(&(NAME))
|
||||
|
||||
#define __lock_close_recursive(NAME) __libc_lock_close_recursive(&(NAME))
|
||||
|
||||
#define __lock_acquire(NAME) __libc_lock_acquire(&(NAME))
|
||||
|
||||
#define __lock_acquire_recursive(NAME) __libc_lock_acquire_recursive(&(NAME))
|
||||
|
||||
#define __lock_try_acquire(NAME) __libc_lock_try_acquire(&(NAME))
|
||||
|
||||
#define __lock_try_acquire_recursive(NAME) __libc_lock_try_acquire_recursive(&(NAME))
|
||||
|
||||
#define __lock_release(NAME) __libc_lock_release(&(NAME))
|
||||
|
||||
#define __lock_release_recursive(NAME) __libc_lock_release_recursive(&(NAME))
|
||||
|
||||
#endif // __SYS_LOCK_H__
|
81
include/3ds/types.h
Normal file
81
include/3ds/types.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* @file types.h
|
||||
* @brief Various system types.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/// The maximum value of a u64.
|
||||
#define U64_MAX UINT64_MAX
|
||||
|
||||
/// would be nice if newlib had this already
|
||||
#ifndef SSIZE_MAX
|
||||
#ifdef SIZE_MAX
|
||||
#define SSIZE_MAX ((SIZE_MAX) >> 1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8; ///< 8-bit unsigned integer
|
||||
typedef uint16_t u16; ///< 16-bit unsigned integer
|
||||
typedef uint32_t u32; ///< 32-bit unsigned integer
|
||||
typedef uint64_t u64; ///< 64-bit unsigned integer
|
||||
|
||||
typedef int8_t s8; ///< 8-bit signed integer
|
||||
typedef int16_t s16; ///< 16-bit signed integer
|
||||
typedef int32_t s32; ///< 32-bit signed integer
|
||||
typedef int64_t s64; ///< 64-bit signed integer
|
||||
|
||||
typedef volatile u8 vu8; ///< 8-bit volatile unsigned integer.
|
||||
typedef volatile u16 vu16; ///< 16-bit volatile unsigned integer.
|
||||
typedef volatile u32 vu32; ///< 32-bit volatile unsigned integer.
|
||||
typedef volatile u64 vu64; ///< 64-bit volatile unsigned integer.
|
||||
|
||||
typedef volatile s8 vs8; ///< 8-bit volatile signed integer.
|
||||
typedef volatile s16 vs16; ///< 16-bit volatile signed integer.
|
||||
typedef volatile s32 vs32; ///< 32-bit volatile signed integer.
|
||||
typedef volatile s64 vs64; ///< 64-bit volatile signed integer.
|
||||
|
||||
typedef u32 Handle; ///< Resource handle.
|
||||
typedef s32 Result; ///< Function result.
|
||||
typedef void (*ThreadFunc)(void*); ///< Thread entrypoint function.
|
||||
typedef void (*voidfn)(void);
|
||||
|
||||
/// Creates a bitmask from a bit number.
|
||||
#define BIT(n) (1U << (n))
|
||||
|
||||
/// Aligns a struct (and other types?) to m, making sure that the size of the struct is a multiple of m.
|
||||
#define ALIGN(m) __attribute__((aligned(m)))
|
||||
/// Packs a struct (and other types?) so it won't include padding bytes.
|
||||
#define PACKED __attribute__((packed))
|
||||
|
||||
#ifndef LIBCTRU_NO_DEPRECATION
|
||||
/// Flags a function as deprecated.
|
||||
#define DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
/// Flags a function as deprecated.
|
||||
#define DEPRECATED
|
||||
#endif
|
||||
|
||||
/// Structure representing CPU registers
|
||||
typedef struct {
|
||||
u32 r[13]; ///< r0-r12.
|
||||
u32 sp; ///< sp.
|
||||
u32 lr; ///< lr.
|
||||
u32 pc; ///< pc. May need to be adjusted.
|
||||
u32 cpsr; ///< cpsr.
|
||||
} CpuRegisters;
|
||||
|
||||
/// Structure representing FPU registers
|
||||
typedef struct {
|
||||
union {
|
||||
struct PACKED {
|
||||
double d[16];
|
||||
}; ///< d0-d15.
|
||||
float s[32]; ///< s0-s31.
|
||||
};
|
||||
u32 fpscr; ///< fpscr.
|
||||
u32 fpexc; ///< fpexc.
|
||||
} FpuRegisters;
|
155
include/3ds/util/utf.h
Normal file
155
include/3ds/util/utf.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @file utf.h
|
||||
* @brief UTF conversion functions.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/** Convert a UTF-8 sequence into a UTF-32 codepoint
|
||||
*
|
||||
* @param[out] out Output codepoint
|
||||
* @param[in] in Input sequence
|
||||
*
|
||||
* @returns number of input code units consumed
|
||||
* @returns -1 for error
|
||||
*/
|
||||
ssize_t decode_utf8(uint32_t* out, const uint8_t* in);
|
||||
|
||||
/** Convert a UTF-16 sequence into a UTF-32 codepoint
|
||||
*
|
||||
* @param[out] out Output codepoint
|
||||
* @param[in] in Input sequence
|
||||
*
|
||||
* @returns number of input code units consumed
|
||||
* @returns -1 for error
|
||||
*/
|
||||
ssize_t decode_utf16(uint32_t* out, const uint16_t* in);
|
||||
|
||||
/** Convert a UTF-32 codepoint into a UTF-8 sequence
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input codepoint
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out must be able to store 4 code units
|
||||
*/
|
||||
ssize_t encode_utf8(uint8_t* out, uint32_t in);
|
||||
|
||||
/** Convert a UTF-32 codepoint into a UTF-16 sequence
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input codepoint
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out must be able to store 2 code units
|
||||
*/
|
||||
ssize_t encode_utf16(uint16_t* out, uint32_t in);
|
||||
|
||||
/** Convert a UTF-8 sequence into a UTF-16 sequence
|
||||
*
|
||||
* Fills the output buffer up to \a len code units.
|
||||
* Returns the number of code units that the input would produce;
|
||||
* if it returns greater than \a len, the output has been
|
||||
* truncated.
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input sequence (null-terminated)
|
||||
* @param[in] len Output length
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out is not null-terminated
|
||||
*/
|
||||
ssize_t utf8_to_utf16(uint16_t* out, const uint8_t* in, size_t len);
|
||||
|
||||
/** Convert a UTF-8 sequence into a UTF-32 sequence
|
||||
*
|
||||
* Fills the output buffer up to \a len code units.
|
||||
* Returns the number of code units that the input would produce;
|
||||
* if it returns greater than \a len, the output has been
|
||||
* truncated.
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input sequence (null-terminated)
|
||||
* @param[in] len Output length
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out is not null-terminated
|
||||
*/
|
||||
ssize_t utf8_to_utf32(uint32_t* out, const uint8_t* in, size_t len);
|
||||
|
||||
/** Convert a UTF-16 sequence into a UTF-8 sequence
|
||||
*
|
||||
* Fills the output buffer up to \a len code units.
|
||||
* Returns the number of code units that the input would produce;
|
||||
* if it returns greater than \a len, the output has been
|
||||
* truncated.
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input sequence (null-terminated)
|
||||
* @param[in] len Output length
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out is not null-terminated
|
||||
*/
|
||||
ssize_t utf16_to_utf8(uint8_t* out, const uint16_t* in, size_t len);
|
||||
|
||||
/** Convert a UTF-16 sequence into a UTF-32 sequence
|
||||
*
|
||||
* Fills the output buffer up to \a len code units.
|
||||
* Returns the number of code units that the input would produce;
|
||||
* if it returns greater than \a len, the output has been
|
||||
* truncated.
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input sequence (null-terminated)
|
||||
* @param[in] len Output length
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out is not null-terminated
|
||||
*/
|
||||
ssize_t utf16_to_utf32(uint32_t* out, const uint16_t* in, size_t len);
|
||||
|
||||
/** Convert a UTF-32 sequence into a UTF-8 sequence
|
||||
*
|
||||
* Fills the output buffer up to \a len code units.
|
||||
* Returns the number of code units that the input would produce;
|
||||
* if it returns greater than \a len, the output has been
|
||||
* truncated.
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input sequence (null-terminated)
|
||||
* @param[in] len Output length
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out is not null-terminated
|
||||
*/
|
||||
ssize_t utf32_to_utf8(uint8_t* out, const uint32_t* in, size_t len);
|
||||
|
||||
/** Convert a UTF-32 sequence into a UTF-16 sequence
|
||||
*
|
||||
* @param[out] out Output sequence
|
||||
* @param[in] in Input sequence (null-terminated)
|
||||
* @param[in] len Output length
|
||||
*
|
||||
* @returns number of output code units produced
|
||||
* @returns -1 for error
|
||||
*
|
||||
* @note \a out is not null-terminated
|
||||
*/
|
||||
ssize_t utf32_to_utf16(uint16_t* out, const uint32_t* in, size_t len);
|
24
include/common.h
Normal file
24
include/common.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
#include "../include/z3D/z3D.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#define BIT_COUNT(x) (sizeof(x) * 8)
|
||||
|
||||
#define TICKS_PER_SEC 268123480
|
||||
#define SEQ_AUDIO_BLANK 0x1000142
|
||||
|
||||
/// Returns 1 if the bit is set in value1 but not in value2, -1 if vice versa, and 0 if they're the same
|
||||
s8 BitCompare(u32 value1, u32 value2, u8 bit);
|
||||
|
||||
u32 Hash(u32);
|
||||
u8 Bias(u32);
|
||||
|
||||
u8 IsInGame(void);
|
||||
u8 IsInGameOrBossChallenge(void);
|
||||
void CitraPrint(const char*, ...);
|
||||
|
||||
#endif //_COMMON_H_
|
145
include/csvc.h
Normal file
145
include/csvc.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/* 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 process Handle of the process.
|
||||
* @param destAddress Address of the mapped block in the current process.
|
||||
* @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 process, u32 destAddr, u32 srcAddr, u32 size);
|
||||
|
||||
/**
|
||||
* @brief Unmaps a block of process memory.
|
||||
* @param process Handle of the process.
|
||||
* @param destAddress Address of the block of memory to unmap, in the current (destination) process.
|
||||
* @param size Size of the block of memory to unmap (truncated to a multiple of 0x1000 bytes).
|
||||
*/
|
||||
Result svcUnmapProcessMemoryEx(Handle process, u32 destAddress, u32 size);
|
||||
|
||||
/**
|
||||
* @brief Queries memory information.
|
||||
* @param[out] info Pointer to output memory info to.
|
||||
* @param out Pointer to output page info to.
|
||||
* @param addr Virtual memory address to query.
|
||||
*/
|
||||
Result svcQueryMemory(MemInfo* info, PageInfo* out, u32 addr);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
///@}
|
119
include/hid.h
Normal file
119
include/hid.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* From n3rdswithgame, who may or may not have originally written this
|
||||
*/
|
||||
|
||||
#ifndef HID_H
|
||||
#define HID_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef union {
|
||||
uint32_t val;
|
||||
struct {
|
||||
uint32_t a : 1; // 1
|
||||
uint32_t b : 1; // 2
|
||||
uint32_t sel : 1; // 3
|
||||
uint32_t strt : 1; // 4
|
||||
uint32_t d_right : 1; // 5
|
||||
uint32_t d_left : 1; // 6
|
||||
uint32_t d_up : 1; // 7
|
||||
uint32_t d_down : 1; // 8
|
||||
uint32_t r : 1; // 9
|
||||
uint32_t l : 1; // 10
|
||||
uint32_t x : 1; // 11
|
||||
uint32_t y : 1; // 12
|
||||
uint32_t gpio : 2; // 14
|
||||
uint32_t padding : 14; // 28
|
||||
uint32_t c_right : 1; // 29
|
||||
uint32_t c_left : 1; // 30
|
||||
uint32_t c_up : 1; // 31
|
||||
uint32_t c_down : 1; // 32
|
||||
};
|
||||
} btn_t;
|
||||
|
||||
typedef union {
|
||||
uint32_t val;
|
||||
struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
};
|
||||
} cp_t;
|
||||
|
||||
typedef struct {
|
||||
btn_t curr;
|
||||
btn_t pressed;
|
||||
btn_t released;
|
||||
cp_t cp;
|
||||
} pad_t;
|
||||
|
||||
struct hid_pad_t {
|
||||
uint64_t timestamp; // 0
|
||||
uint64_t timestamp_last; // 8
|
||||
uint32_t index; // 10
|
||||
uint32_t pad_14[2]; // 14
|
||||
btn_t btn_raw; // 1c
|
||||
cp_t cp_raw; // 20
|
||||
uint8_t pad_24; // 24
|
||||
pad_t pads[8];
|
||||
};
|
||||
|
||||
struct touch_input_t {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct touch_input_t touch;
|
||||
uint32_t updated;
|
||||
} touch_t;
|
||||
|
||||
struct hid_touch_t {
|
||||
uint64_t timestamp; // 0
|
||||
uint64_t timestamp_last; // 8
|
||||
uint32_t index; // 10
|
||||
uint32_t pad_14; // 14
|
||||
touch_t raw;
|
||||
touch_t touches[8];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct hid_pad_t pad;
|
||||
struct hid_touch_t touch;
|
||||
} hid_mem_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t field_00;
|
||||
struct hid_pad_t* hid_pad;
|
||||
uint32_t field_08;
|
||||
struct hid_touch_t* hid_touch;
|
||||
uint32_t field_10;
|
||||
uint32_t* hid_accl; // need to add
|
||||
uint32_t field_18;
|
||||
uint32_t field_1c;
|
||||
uint32_t* hid_gyro; // need to add
|
||||
uint32_t field_24;
|
||||
uint32_t* hid_debug; // might add
|
||||
uint32_t mappable_mem_chunk[4]; // need to add
|
||||
uint32_t bool_3c;
|
||||
uint32_t hid_handle;
|
||||
uint32_t bool_44;
|
||||
} hid_ctx_t;
|
||||
|
||||
#define BUTTON_A (1 << 0)
|
||||
#define BUTTON_B (1 << 1)
|
||||
#define BUTTON_SELECT (1 << 2)
|
||||
#define BUTTON_START (1 << 3)
|
||||
#define BUTTON_RIGHT (1 << 4)
|
||||
#define BUTTON_LEFT (1 << 5)
|
||||
#define BUTTON_UP (1 << 6)
|
||||
#define BUTTON_DOWN (1 << 7)
|
||||
#define BUTTON_R1 (1 << 8)
|
||||
#define BUTTON_L1 (1 << 9)
|
||||
#define BUTTON_X (1 << 10)
|
||||
#define BUTTON_Y (1 << 11)
|
||||
#define CPAD_RIGHT (1 << 28)
|
||||
#define CPAD_LEFT (1 << 29)
|
||||
#define CPAD_UP (1 << 30)
|
||||
#define CPAD_DOWN (1 << 31)
|
||||
|
||||
#endif // HID_H
|
21
include/input.h
Normal file
21
include/input.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "z3D/z3D.h"
|
||||
#include "hid.h"
|
||||
#include "3ds/services/irrst.h"
|
||||
|
||||
typedef struct {
|
||||
btn_t cur;
|
||||
btn_t up;
|
||||
btn_t pressed;
|
||||
btn_t old;
|
||||
int16_t touchX;
|
||||
int16_t touchY;
|
||||
uint32_t touchPressed;
|
||||
uint32_t touchHeld;
|
||||
circlePosition cStick;
|
||||
} InputContext;
|
||||
|
||||
void Input_Update(void);
|
||||
u32 Input_WaitWithTimeout(u32 msec, u32 closingButton);
|
||||
u32 Input_Wait(void);
|
||||
|
||||
extern InputContext rInputCtx;
|
108
include/lib/printf.h
Normal file
108
include/lib/printf.h
Normal file
@@ -0,0 +1,108 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PRINTF_H_
|
||||
#define _PRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Output a character to a custom device like UART, used by the printf() function
|
||||
* This function is declared here only. You have to write your custom implementation somewhere
|
||||
* \param character Character to output
|
||||
*/
|
||||
void _putchar(char character);
|
||||
|
||||
/**
|
||||
* Tiny printf implementation
|
||||
* You have to implement _putchar if you use printf()
|
||||
* To avoid conflicts with the regular printf() API it is overridden by macro defines
|
||||
* and internal underscore-appended functions like printf_() are used
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are written into the array, not counting the terminating null character
|
||||
*/
|
||||
#define printf printf_
|
||||
int printf_(const char* format, ...);
|
||||
|
||||
/**
|
||||
* Tiny sprintf implementation
|
||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define sprintf sprintf_
|
||||
int sprintf_(char* buffer, const char* format, ...);
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||
* is non-negative and less than count, the string has been completely written.
|
||||
*/
|
||||
#define snprintf snprintf_
|
||||
#define vsnprintf vsnprintf_
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...);
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
|
||||
|
||||
/**
|
||||
* Tiny vprintf implementation
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define vprintf vprintf_
|
||||
int vprintf_(const char* format, va_list va);
|
||||
|
||||
/**
|
||||
* printf with output function
|
||||
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||
* \param out An output function which takes one character and an argument pointer
|
||||
* \param arg An argument pointer for user data passed to output function
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||
*/
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _PRINTF_H_
|
14
include/lib/string.h
Normal file
14
include/lib/string.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/types.h"
|
||||
#include <stdint.h>
|
||||
|
||||
size_t strlen(const char* str);
|
||||
|
||||
void* memset(void* ptr, int value, size_t num);
|
||||
|
||||
void* memcpy(void* dst, const void* src, size_t len);
|
||||
|
||||
size_t strnlen(const char* s, size_t max_len);
|
||||
|
||||
char* strncpy(char* dst, const char* src, size_t num);
|
3
include/lib/types.h
Normal file
3
include/lib/types.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
typedef unsigned int size_t;
|
7
include/loader.h
Normal file
7
include/loader.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "newcodeinfo.h"
|
||||
#include "3ds/types.h"
|
||||
|
||||
Result svcControlProcessMemory(Handle process, u32 addr0, u32 addr1, u32 size, u32 type, u32 perm);
|
||||
|
||||
Handle getCurrentProcessHandle(void)
|
||||
__attribute__((section (".loader")));
|
12
include/newcodeinfo.h
Normal file
12
include/newcodeinfo.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* This file will (eventually) be automatically generated, following
|
||||
* the method used by RicBent in the program Magikoopa
|
||||
*/
|
||||
|
||||
#ifndef _NEWCODEINFO_H_
|
||||
#define _NEWCODEINFO_H_
|
||||
|
||||
#define NEWCODE_OFFSET 0x005C7000 //TODO: this
|
||||
#define NEWCODE_SIZE 0x0002E000 //TODO: this. even now, this is too big.
|
||||
|
||||
#endif //_NEWCODEINFO_H_
|
59
include/utils.h
Normal file
59
include/utils.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "3ds/svc.h"
|
||||
#include "3ds/result.h"
|
||||
#include "csvc.h"
|
||||
|
||||
// For accessing physmem uncached (and directly)
|
||||
#define PA_PTR(addr) (void*)((u32)(addr) | 1 << 31)
|
||||
|
||||
#ifndef PA_FROM_VA_PTR
|
||||
#define PA_FROM_VA_PTR(addr) PA_PTR(svcConvertVAToPA((const void*)(addr), false))
|
||||
#endif
|
||||
|
||||
#define REG32(addr) (*(vu32*)(PA_PTR(addr)))
|
||||
|
||||
static inline u32 makeARMBranch(const void* src, const void* dst, bool link) // the macros for those are ugly and buggy
|
||||
{
|
||||
u32 instrBase = link ? 0xEB000000 : 0xEA000000;
|
||||
u32 off = (u32)((const u8*)dst -
|
||||
((const u8*)src + 8)); // the PC is always two instructions ahead of the one being executed
|
||||
|
||||
return instrBase | ((off >> 2) & 0xFFFFFF);
|
||||
}
|
||||
|
||||
static inline void* decodeARMBranch(const void* src) {
|
||||
u32 instr = *(const u32*)src;
|
||||
s32 off = (instr & 0xFFFFFF) << 2;
|
||||
off = (off << 6) >> 6; // sign extend
|
||||
|
||||
return (void*)((const u8*)src + 8 + off);
|
||||
}
|
||||
|
||||
Result OpenProcessByName(const char* name, Handle* h);
|
837
include/z3D/z3D.h
Normal file
837
include/z3D/z3D.h
Normal file
@@ -0,0 +1,837 @@
|
||||
#ifndef _Z3D_H_
|
||||
#define _Z3D_H_
|
||||
|
||||
#include "z3Dactor.h"
|
||||
#include "z3Dvec.h"
|
||||
#include "z3Dcutscene.h"
|
||||
#include "z3Ditem.h"
|
||||
|
||||
// #include "hid.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u8 buttonItems[5]; // B,Y,X,I,II
|
||||
/* 0x05 */ u8 buttonSlots[4]; // Y,X,I,II
|
||||
/* 0x0A */ u16 equipment;
|
||||
} ItemEquips; // size = 0x0C
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u32 chest;
|
||||
/* 0x04 */ u32 swch;
|
||||
/* 0x08 */ u32 clear;
|
||||
/* 0x0C */ u32 collect;
|
||||
/* 0x10 */ u32 unk;
|
||||
/* 0x14 */ u32 rooms1;
|
||||
/* 0x18 */ u32 rooms2;
|
||||
} SaveSceneFlags; // size = 0x1C
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s16 scene;
|
||||
/* 0x02 */ Vec3s pos;
|
||||
/* 0x08 */ s16 angle;
|
||||
} HorseData; // size = 0x0A
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ Vec3f pos;
|
||||
/* 0x0C */ s16 yaw;
|
||||
/* 0x0E */ s16 playerParams;
|
||||
/* 0x10 */ s16 entranceIndex;
|
||||
/* 0x12 */ u8 roomIndex;
|
||||
/* 0x13 */ u8 data;
|
||||
/* 0x14 */ u32 tempSwchFlags;
|
||||
/* 0x18 */ u32 tempCollectFlags;
|
||||
} RespawnData; // size = 0x1C
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ RESPAWN_MODE_DOWN, /* Normal Void Outs */
|
||||
/* 0x01 */ RESPAWN_MODE_RETURN, /* Grotto Returnpoints */
|
||||
/* 0x02 */ RESPAWN_MODE_TOP /* Farore's Wind */
|
||||
} RespawnMode;
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ BTN_ENABLED,
|
||||
/* 0xFF */ BTN_DISABLED = 0xFF
|
||||
} ButtonStatus;
|
||||
|
||||
// Save Context (ram start: 0x00587958)
|
||||
typedef struct {
|
||||
/* 0x0000 */ s32 entranceIndex;
|
||||
/* 0x0004 */ s32 linkAge; // 0: Adult; 1: Child
|
||||
/* 0x0008 */ s32 cutsceneIndex;
|
||||
/* 0x000C */ u16 dayTime; // "zelda_time"
|
||||
/* 0x000E */ u8 masterQuestFlag;
|
||||
/* 0x000F */ u8 motionControlSetting;
|
||||
/* 0x0010 */ s32 nightFlag;
|
||||
/* 0x0014 */ s32 unk_14;
|
||||
/* 0x0018 */ s32 unk_18;
|
||||
/* 0x001C */ s16 playerName[0x8];
|
||||
/* 0x002C */ u8 playerNameLength;
|
||||
/* 0x002D */ u8 zTargetingSetting;
|
||||
/* 0x002E */ s16 unk_2E;
|
||||
/* 0x0030 */ char newf[6]; // string "ZELDAZ"
|
||||
/* 0x0036 */ u16 saveCount;
|
||||
/* 0x0038 */ char unk_38[0x000A];
|
||||
/* 0x0042 */ u16 healthCapacity; // "max_life"
|
||||
/* 0x0044 */ s16 health; // "now_life"
|
||||
/* 0x0046 */ s8 magicLevel;
|
||||
/* 0x0047 */ s8 magic;
|
||||
/* 0x0048 */ s16 rupees;
|
||||
/* 0x004A */ u16 bgsHitsLeft;
|
||||
/* 0x004C */ u16 naviTimer;
|
||||
/* 0x004E */ u8 magicAcquired;
|
||||
/* 0x004F */ char unk_4F[0x0001];
|
||||
/* 0x0050 */ u8 doubleMagic;
|
||||
/* 0x0051 */ u8 doubleDefense;
|
||||
/* 0x0052 */ s8 bgsFlag;
|
||||
/* 0x0054 */ ItemEquips childEquips;
|
||||
/* 0x0060 */ ItemEquips adultEquips;
|
||||
/* 0x006C */ char unk_6C[0x0012];
|
||||
/* 0x007E */ u16 sceneIndex;
|
||||
/* 0x0080 */ ItemEquips equips;
|
||||
/* 0x008C */ u8 items[26];
|
||||
/* 0x00A6 */ s8 ammo[15];
|
||||
/* 0x00B5 */ u8 magic_beans_available; // counts bought
|
||||
/* 0x00B6 */ u16 equipment; // bits: swords 0-3, shields 4-6, tunics 8-10, boots 12-14
|
||||
/* 0x00B8 */ u32 upgrades; // bits: quiver 0-2, bombs 3-5, strength 6-8, dive 9-11, wallet 12-13, seeds 14-16,
|
||||
// sticks 17-19, nuts 20-22
|
||||
/* 0x00BC */ u32 questItems; // bits: medallions 0-5, warp songs 6-11, songs 12-17, stones 18-20, shard 21, token
|
||||
// 22, skull 23, heart pieces 24-31
|
||||
/* 0x00C0 */ u8 dungeonItems[20]; // bits: boss key 0, compass 1, map 2
|
||||
/* 0x00D4 */ s8 dungeonKeys[19];
|
||||
/* 0x00E7 */ char unk_E7[0x0001]; // in oot: defenseHearts. seems not here.
|
||||
/* 0x00E8 */ s16 gsTokens;
|
||||
/* 0x00EC */ SaveSceneFlags sceneFlags[124];
|
||||
struct {
|
||||
/* 0x0E7C */ Vec3i pos;
|
||||
/* 0x0E88 */ s32 yaw;
|
||||
/* 0x0E8C */ s32 playerParams;
|
||||
/* 0x0E90 */ s32 entranceIndex;
|
||||
/* 0x0E94 */ s32 roomIndex;
|
||||
/* 0x0E98 */ s32 set;
|
||||
/* 0x0E9C */ s32 tempSwchFlags;
|
||||
/* 0x0EA0 */ s32 tempCollectFlags;
|
||||
} fw;
|
||||
/* 0x0EA4 */ char unk_EA4[0x0010];
|
||||
/* 0x0EB4 */ u8 gsFlags[22]; // due to reordering, array is smaller
|
||||
/* 0x0ECA */ char unk_ECA[0x0006]; // the extra two bytes move here
|
||||
/* 0x0ED0 */ u32 unk_ED0; // horseback archery highscore?
|
||||
/* 0x0ED4 */ u32 bigPoePoints; // number of big poes sold * 100
|
||||
struct {
|
||||
/* 0x0ED4 */ u8 recordFishChild; // seems to be unique ID of fish, this is copied into adult value if player has
|
||||
// not yet fished as adult
|
||||
/* 0x0ED5 */ u8 flags; // bits: 0 - ever fished as child, 1 - ever fished as adult, 2 - caught record as child,
|
||||
// 3 - caught record as adult
|
||||
/* 0x0ED6 */ u8 timesPaidToFish;
|
||||
/* 0x0ED7 */ u8 recordFishAdult; // seems to be unique ID of fish
|
||||
} fishingStats;
|
||||
/* 0x0EDC */ u32 unk_EDC; // horse race record time?
|
||||
/* 0x0EE0 */ u32 unk_EE0; // marathon race record time?
|
||||
/* 0x0EE4 */ char unk_EE4[0x0008];
|
||||
/* 0x0EEC */ u16 eventChkInf[14]; // "event_chk_inf"
|
||||
/* 0x0F08 */ u16 itemGetInf[4]; // "item_get_inf"
|
||||
/* 0x0F10 */ u16 infTable[30]; // "inf_table"
|
||||
/* 0x0F4C */ char unk_F34[0x0004];
|
||||
/* 0x0F50 */ u32 worldMapAreaData; // "area_arrival"
|
||||
/* 0x0F54 */ char unk_F54[0x0410]; // TODO: scarecrow's song
|
||||
/* 0x1364 */ HorseData horseData;
|
||||
/* 0x136E */ char unk_136E[0x0002];
|
||||
/* 0x1370 */ u8 itemSlotDataRecords[26];
|
||||
/* 0x138A */ u8 itemMenuChild[24];
|
||||
/* 0x13A2 */ u8 itemMenuAdult[24];
|
||||
/* 0x13BA */ char unk_13BA[0x0002];
|
||||
struct {
|
||||
/* 0x13BC */ u32 year;
|
||||
/* 0x13C0 */ u32 month;
|
||||
/* 0x13C4 */ u32 day;
|
||||
/* 0x13C8 */ u32 hour;
|
||||
/* 0x13CC */ u32 minute;
|
||||
} saveTime;
|
||||
/* 0x13D0 */ char unk_13D0[0x0004];
|
||||
/* 0x13D4 */ u8 otherNewEventFlags; // Club Moblin cutscene and Sheikah Stone Navi message
|
||||
/* 0x13D5 */ char unk_13D5[0x0003];
|
||||
/* 0x13D8 */ u8 cameraControlSetting;
|
||||
/* 0x13D9 */ char unk_13D9[0x0077];
|
||||
/* 0x1450 */ u32 bossBattleVictories[9];
|
||||
/* 0x1474 */ u32 bossBattleScores[9];
|
||||
/* 0x1498 */ char unk_1498[0x0040]; // sheikah stone flags?
|
||||
/* 0x14D8 */ u16 checksum; // "check_sum"
|
||||
/* 0x14DC */ s32 fileNum; // "file_no"
|
||||
/* 0x14E0 */ char unk_14E0[0x0004];
|
||||
/* 0x14E4 */ s32 gameMode;
|
||||
/* 0x14E8 */ s32 sceneSetupIndex;
|
||||
/* 0x14EC */ s32 respawnFlag; // "restart_flag"
|
||||
/* 0x14F0 */ RespawnData respawn[3]; // "restart_data"
|
||||
/* 0x1544 */ char unk_1544[0x000E];
|
||||
/* 0x1552 */ s16 nayrusLoveTimer;
|
||||
/* 0x1554 */ char unk_1554[0x0008];
|
||||
/* 0x155C */ s16 rupeeAccumulator;
|
||||
/* 0x155E */ s16 timer1State;
|
||||
/* 0x1560 */ s16 timer1Value;
|
||||
/* 0x1562 */ s16 timer2State;
|
||||
/* 0x1564 */ s16 timer2Value;
|
||||
/* 0x1566 */ s16 timerX[2]; // changing these doesn't seem to actually move the timer?
|
||||
/* 0x156A */ s16 timerY[2]; // changing these doesn't seem to actually move the timer?
|
||||
/* 0x156E */ u8 nightSeqIndex;
|
||||
/* 0x156F */ u8 buttonStatus[5];
|
||||
/* 0x1574 */ char unk_1574[0x000B];
|
||||
/* 0x1580 */ s16 magicState;
|
||||
/* 0x1582 */ char unk_1582[0x0002];
|
||||
/* 0x1584 */ u16 magicMeterSize;
|
||||
/* 0x1586 */ char unk_1586[0x0002];
|
||||
/* 0x1588 */ s16 magicTarget;
|
||||
/* 0x158A */ u16 eventInf[4];
|
||||
/* 0x1592 */ u16 dungeonIndex;
|
||||
/* 0x1594 */ char unk_1594[0x000C];
|
||||
/* 0x15A0 */ u16 nextCutsceneIndex;
|
||||
/* 0x15A2 */ u8 cutsceneTrigger;
|
||||
/* 0x15A3 */ char unk_15A3[0x008];
|
||||
/* 0x15AB */ u8 nextTransition;
|
||||
/* 0x15AC */ char unk_15AC[0x006];
|
||||
/* 0x15B2 */ s16 healthAccumulator;
|
||||
|
||||
// stuff below is from z64.h
|
||||
/* skipped over */
|
||||
// /* 0x0022 */ s16 deaths;
|
||||
// /* 0x002C */ s16 n64ddFlag;
|
||||
// /* 0x0072 */ char unk_72[0x0002];
|
||||
// /* 0x00CF */ s8 defenseHearts;
|
||||
// /* 0x0F3C */ char unk_F3C[0x040C];
|
||||
// /* 0x13BC */ char unk_13BC[0x0008];
|
||||
// /* 0x13C4 */ s16 dogParams;
|
||||
// /* 0x13C6 */ char unk_13C6[0x0001];
|
||||
// /* 0x13C7 */ u8 unk_13C7;
|
||||
|
||||
/* still to compare */
|
||||
// /* 0x13CA */ char unk_13CA[0x0002];
|
||||
|
||||
// /* 0x13DE */ char unk_13DE[0x0002];
|
||||
// /* 0x13E0 */ u8 seqIndex;
|
||||
// /* 0x13E1 */ u8 nightSeqIndex;
|
||||
// /* 0x13E2 */ u8 buttonStatus[5];
|
||||
// /* 0x13E7 */ u8 unk_13E7;
|
||||
// /* 0x13E8 */ u16 unk_13E8; // alpha type?
|
||||
// /* 0x13EA */ u16 unk_13EA; // also alpha type?
|
||||
// /* 0x13EC */ u16 unk_13EC; // alpha type counter?
|
||||
// /* 0x13EE */ u16 unk_13EE; // previous alpha type?
|
||||
// /* 0x13F0 */ s16 unk_13F0;
|
||||
// /* 0x13F2 */ s16 unk_13F2;
|
||||
// /* 0x13F4 */ s16 unk_13F4;
|
||||
// /* 0x13F6 */ s16 unk_13F6;
|
||||
// /* 0x13F8 */ s16 unk_13F8;
|
||||
// /* 0x13FA */ u16 eventInf[4]; // "event_inf"
|
||||
// /* 0x1404 */ u16 minigameState;
|
||||
// /* 0x1406 */ u16 minigameScore; // "yabusame_total"
|
||||
// /* 0x1408 */ char unk_1408[0x0001];
|
||||
// /* 0x1409 */ u8 language;
|
||||
// /* 0x140A */ u8 audioSetting;
|
||||
// /* 0x140B */ char unk_140B[0x0001];
|
||||
// /* 0x140C */ u8 zTargetingSetting; // 0: Switch; 1: Hold
|
||||
// /* 0x140E */ u16 unk_140E; // bgm related
|
||||
// /* 0x1410 */ u8 unk_1410;
|
||||
// /* 0x1411 */ u8 unk_1411;
|
||||
// /* 0x1412 */ u16 nextCutsceneIndex;
|
||||
// /* 0x1414 */ u8 cutsceneTrigger;
|
||||
// /* 0x1415 */ u8 chamberCutsceneNum;
|
||||
// /* 0x1416 */ u16 nextDayTime; // "next_zelda_time"
|
||||
// /* 0x1418 */ u8 fadeDuration;
|
||||
// /* 0x1419 */ u8 unk_1419; // transition related
|
||||
// /* 0x141A */ u16 environmentTime;
|
||||
// /* 0x141C */ u8 dogIsLost;
|
||||
// /* 0x141D */ u8 nextTransition;
|
||||
// /* 0x141E */ char unk_141E[0x0002];
|
||||
// /* 0x1420 */ s16 worldMapArea;
|
||||
// /* 0x1422 */ s16 unk_1422; // day time related
|
||||
} SaveContext; // size = 0x15C4
|
||||
|
||||
typedef struct GraphicsContext GraphicsContext; // TODO
|
||||
typedef struct GlobalContext GlobalContext;
|
||||
typedef struct {
|
||||
/* 0x000 */ char unk_000[0x080];
|
||||
/* 0x080 */ Vec3f at;
|
||||
/* 0x08C */ Vec3f eye;
|
||||
/* 0x098 */ Vec3f up;
|
||||
/* 0x0A4 */ Vec3f eyeNext;
|
||||
/* 0x0B0 */ Vec3f skyboxOffset;
|
||||
/* 0x0BC */ char unk_0BC[0x018];
|
||||
/* 0x0D4 */ GlobalContext* globalCtx;
|
||||
/* 0x0D8 */ Player* player;
|
||||
/* 0x0DC */ PosRot playerPosRot;
|
||||
/* 0x0F0 */ Actor* target;
|
||||
/* 0x0F4 */ PosRot targetPosRot;
|
||||
/* 0x108 */ f32 rUpdateRateInv;
|
||||
/* 0x10C */ f32 pitchUpdateRateInv;
|
||||
/* 0x110 */ f32 yawUpdateRateInv;
|
||||
/* 0x114 */ f32 xzOffsetUpdateRate;
|
||||
/* 0x118 */ f32 yOffsetUpdateRate;
|
||||
/* 0x11C */ f32 fovUpdateRate;
|
||||
/* 0x120 */ f32 xzSpeed;
|
||||
/* 0x124 */ f32 dist;
|
||||
/* 0x128 */ f32 speedRatio;
|
||||
/* 0x12C */ Vec3f playerToAtOffset;
|
||||
/* 0x138 */ Vec3f playerPosDelta;
|
||||
/* 0x144 */ f32 fov;
|
||||
/* 0x148 */ f32 atLERPStepScale;
|
||||
/* 0x14C */ f32 playerGroundY;
|
||||
/* 0x150 */ Vec3f floorNorm;
|
||||
/* 0x15C */ f32 waterYPos;
|
||||
/* 0x160 */ s32 waterPrevCamIdx;
|
||||
/* 0x164 */ s32 waterPrevCamSetting;
|
||||
/* 0x168 */ s32 waterQuakeIdx;
|
||||
/* 0x16C */ char unk_16C[0x00C];
|
||||
/* 0x178 */ s16 uid;
|
||||
/* 0x17A */ char unk_17A[0x002];
|
||||
/* 0x17C */ Vec3s inputDir;
|
||||
/* 0x182 */ Vec3s camDir;
|
||||
/* 0x188 */ s16 status;
|
||||
/* 0x18A */ s16 setting;
|
||||
/* 0x18C */ s16 mode;
|
||||
/* 0x18E */ s16 bgCheckId;
|
||||
/* 0x190 */ s16 camDataIdx;
|
||||
/* 0x192 */ s16 behaviorFlags;
|
||||
/* 0x194 */ s16 stateFlags;
|
||||
/* 0x196 */ s16 childCamIdx;
|
||||
/* 0x198 */ s16 waterDistortionTimer;
|
||||
/* 0x19A */ s16 distortionFlags;
|
||||
/* 0x19C */ s16 prevSetting;
|
||||
/* 0x19E */ s16 nextCamDataIdx;
|
||||
/* 0x1A0 */ s16 nextBgCheckId;
|
||||
/* 0x1A2 */ s16 roll;
|
||||
/* 0x1A4 */ s16 paramFlags;
|
||||
/* 0x1A6 */ s16 animState;
|
||||
/* 0x1A8 */ s16 timer;
|
||||
/* 0x1AA */ s16 parentCamIdx;
|
||||
/* 0x1AC */ s16 thisIdx;
|
||||
/* 0x1AE */ s16 prevCamDataIdx;
|
||||
/* 0x1B0 */ s16 csId;
|
||||
/* 0x1B2 */ char unk_1B2[0x00A];
|
||||
} Camera; // size = 0x1BC
|
||||
|
||||
typedef struct {
|
||||
/* 0x0 */ u16 setting;
|
||||
/* 0x2 */ s16 count;
|
||||
/* 0x4 */ Vec3s* camFuncData;
|
||||
} CamData; // size = 0x8
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ Vec3f atOffset;
|
||||
/* 0x0C */ Vec3f eyeOffset;
|
||||
/* 0x18 */ s16 upPitchOffset;
|
||||
/* 0x1A */ s16 upYawOffset;
|
||||
/* 0x1C */ s16 fovOffset;
|
||||
/* 0x20 */ f32 maxOffset;
|
||||
} ShakeInfo; // size = 0x24
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ char unk_00[0x04];
|
||||
/* 0x04 */ Vec3s minBounds;
|
||||
/* 0x0A */ Vec3s maxBounds;
|
||||
/* 0x10 */ u16 numVertices;
|
||||
/* 0x12 */ u16 numPolygons;
|
||||
/* 0x14 */ u16 numWaterboxes;
|
||||
/* 0x18 */ Vec3s* vtxList;
|
||||
/* 0x1C */ CollisionPoly* polyList;
|
||||
/* 0x20 */ void* surfaceTypeList;
|
||||
/* 0x24 */ CamData* camDataList;
|
||||
/* 0x28 */ void* waterboxes;
|
||||
} CollisionHeader; // size = 0x2C
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ CollisionHeader* colHeader;
|
||||
/* 0x04 */ char unk_04[0x4C];
|
||||
} StaticCollisionContext; // size = 0x50
|
||||
|
||||
typedef struct {
|
||||
/* 0x0000 */ char unk_00[0x04];
|
||||
/* 0x0004 */ ActorMesh actorMeshArr[50];
|
||||
/* 0x151C */ u16 flags[50];
|
||||
/* 0x1580 */ char unk_13F0[0x24];
|
||||
} DynaCollisionContext; // size = 0x15A4
|
||||
|
||||
typedef struct {
|
||||
/* 0x0000 */ StaticCollisionContext stat;
|
||||
/* 0x0050 */ DynaCollisionContext dyna;
|
||||
} CollisionContext; // size = 0x15F4
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u8* texture;
|
||||
/* 0x04 */ s16 x;
|
||||
/* 0x06 */ s16 y;
|
||||
/* 0x08 */ s16 width;
|
||||
/* 0x0A */ s16 height;
|
||||
/* 0x0C */ s32 unk_0C;
|
||||
/* 0x10 */ u8 durationTimer;
|
||||
/* 0x11 */ u8 delayTimer;
|
||||
/* 0x12 */ s16 alpha;
|
||||
/* 0x14 */ s16 intensity;
|
||||
/* 0x16 */ s16 unk_16;
|
||||
} TitleCardContext; // size = 0x18
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u32 length; // number of actors loaded of this type
|
||||
/* 0x04 */ Actor* first; // pointer to first actor of this type
|
||||
} ActorListEntry; // size = 0x08
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u32 swch;
|
||||
/* 0x04 */ u32 tempSwch;
|
||||
/* 0x08 */ u32 unk0;
|
||||
/* 0x0C */ u32 unk1;
|
||||
/* 0x10 */ u32 chest;
|
||||
/* 0x14 */ u32 clear;
|
||||
/* 0x18 */ u32 tempClear;
|
||||
/* 0x1C */ u32 collect;
|
||||
/* 0x20 */ u32 tempCollect;
|
||||
} ActorFlags; // size = 0x24
|
||||
|
||||
typedef struct {
|
||||
/* 0x0000 */ u8 unk_00;
|
||||
/* 0x0001 */ char unk_01[0x01];
|
||||
/* 0x0002 */ u8 unk_02;
|
||||
/* 0x0003 */ u8 unk_03;
|
||||
/* 0x0004 */ char unk_04[0x04];
|
||||
/* 0x0008 */ u8 total; // total number of actors loaded
|
||||
/* 0x0009 */ char unk_09[0x03];
|
||||
/* 0x000C */ ActorListEntry actorList[12];
|
||||
// /* 0x006C */ TargetContext targetCtx;
|
||||
/* 0x006C */ char unk_6C[0x130];
|
||||
/* 0x019C */ ActorFlags flags;
|
||||
/* 0x01C0 */ TitleCardContext titleCtx;
|
||||
} ActorContext; // TODO: size = 0x1D8
|
||||
|
||||
typedef struct CutsceneContext {
|
||||
/* 0x00 */ char unk_00[0x4];
|
||||
/* 0x04 */ void* segment;
|
||||
/* 0x08 */ u8 state;
|
||||
/* 0x09 */ char unk_09[0x13];
|
||||
/* 0x1C */ f32 unk_1C;
|
||||
/* 0x20 */ u16 frames;
|
||||
/* 0x22 */ u16 unk_22;
|
||||
/* 0x24 */ s32 unk_24;
|
||||
/* 0x28 */ char unk_28[0x18];
|
||||
/* 0x40 */ CsCmdActorAction* linkAction;
|
||||
/* 0x44 */ CsCmdActorAction* actorActions[10]; // "npcdemopnt"
|
||||
} CutsceneContext; // size = 0x6C
|
||||
|
||||
typedef struct Sub_118_C {
|
||||
s32 data[4];
|
||||
} Sub_118_C;
|
||||
|
||||
typedef struct SubGlobalContext_118 {
|
||||
/* 0x00 */ char unk_00[0x0C];
|
||||
/* 0x0C */ Sub_118_C* sub0C; // an array of these
|
||||
/* 0x10 */ char unk_10[0x24];
|
||||
/* 0x34 */ s32 indexInto0C;
|
||||
/* 0x38 */ char unk_38[0x28];
|
||||
/* 0x60 */ void** unk_60; // seems to point to an array of cutscene pointers, maybe?
|
||||
} SubGlobalContext_118; // size = at least 0x64
|
||||
|
||||
typedef struct OcLine OcLine; // TODO
|
||||
#define COLLISION_CHECK_AT_MAX 50
|
||||
#define COLLISION_CHECK_AC_MAX 60
|
||||
#define COLLISION_CHECK_OC_MAX 50
|
||||
#define COLLISION_CHECK_OC_LINE_MAX 3
|
||||
|
||||
typedef struct {
|
||||
/* 0x000 */ s16 colAtCount;
|
||||
/* 0x002 */ u16 sacFlags;
|
||||
/* 0x004 */ Collider* colAt[COLLISION_CHECK_AT_MAX];
|
||||
/* 0x0CC */ s32 colAcCount;
|
||||
/* 0x0D0 */ Collider* colAc[COLLISION_CHECK_AC_MAX];
|
||||
/* 0x1C0 */ s32 colOcCount;
|
||||
/* 0x1C4 */ Collider* colOc[COLLISION_CHECK_OC_MAX];
|
||||
/* 0x28C */ s32 colOcLineCount;
|
||||
/* 0x290 */ OcLine* colOcLine[COLLISION_CHECK_OC_LINE_MAX];
|
||||
|
||||
} CollisionCheckContext; // size = 0x29C
|
||||
// _Static_assert(sizeof(CollisionCheckContext) == 0x29C, "CollisionCheckContext size");
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ Vec3f pos;
|
||||
/* 0x0C */ Vec3f norm;
|
||||
/* 0x18 */ CollisionPoly* poly;
|
||||
struct {
|
||||
/* 0x1C */ f32 radius;
|
||||
/* 0x20 */ s16 pitch;
|
||||
/* 0x22 */ s16 yaw;
|
||||
} geoNorm;
|
||||
/* 0x24 */ s32 bgId;
|
||||
} CamColChk; // size = 0x28
|
||||
|
||||
#define OBJECT_EXCHANGE_BANK_MAX 19
|
||||
#define OBJECT_ID_MAX 417
|
||||
|
||||
typedef struct ZARInfo {
|
||||
/* 0x00 */ void* buf;
|
||||
/* 0x04 */ char unk_04[0x48];
|
||||
/* 0x4C */ void*** cmbPtrs; /* Really, this is a pointer to an array of pointers to CMB managers,
|
||||
the first member of which is a pointer to the CMB data */
|
||||
/* 0x50 */ void*** csabPtrs; /* Same as above but for CSAB */
|
||||
/* 0x54 */ char unk_54[0x04];
|
||||
/* 0x58 */ void*** cmabPtrs; /* Same as above but for CMAB */
|
||||
/* 0x5C */ char unk_5C[0x14];
|
||||
} ZARInfo; // size = 0x70
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s16 id;
|
||||
/* 0x02 */ char unk_02[0x0E];
|
||||
/* 0x10 */ ZARInfo zarInfo;
|
||||
} ObjectStatus; // size = 0x80
|
||||
|
||||
typedef struct {
|
||||
/* 0x000 */ u8 num;
|
||||
/* 0x001 */ char unk_01[0x3];
|
||||
/* 0x004 */ ObjectStatus status[OBJECT_EXCHANGE_BANK_MAX];
|
||||
} ObjectContext; // size = 0x984
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ char filename[0x40];
|
||||
/* 0x40 */ u32 size;
|
||||
} ObjectFile;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s16 id;
|
||||
/* 0x02 */ Vec3s pos;
|
||||
/* 0x08 */ Vec3s rot;
|
||||
/* 0x0E */ s16 params;
|
||||
} ActorEntry; // size = 0x10
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u8 spawn;
|
||||
/* 0x01 */ u8 room;
|
||||
} EntranceEntry;
|
||||
|
||||
typedef struct GameState {
|
||||
/* 0x00 */ GraphicsContext* gfxCtx;
|
||||
/* 0x04 */ void (*main)(struct GameState*);
|
||||
/* 0x08 */ void (*destroy)(struct GameState*); // "cleanup"
|
||||
/* 0x0C */ void (*init)(struct GameState*);
|
||||
// TODO
|
||||
} GameState;
|
||||
|
||||
// Global Context (ram start: 0871E840)
|
||||
typedef struct GlobalContext {
|
||||
// /* 0x0000 */ GameState state;
|
||||
/* 0x0000 */ char unk_0[0x0104];
|
||||
/* 0x0104 */ s16 sceneNum;
|
||||
/* 0x0106 */ char unk_106[0x0012];
|
||||
/* 0x0118 */ SubGlobalContext_118 sub118;
|
||||
/* 0x017C */ char unk_17C[0x000C];
|
||||
struct {
|
||||
/* 0x0188 */ s32 topY;
|
||||
/* 0x018C */ s32 bottomY;
|
||||
/* 0x0190 */ s32 leftX;
|
||||
/* 0x0194 */ s32 rightX;
|
||||
/* 0x0198 */ f32 fovY;
|
||||
/* 0x019C */ f32 zNear;
|
||||
/* 0x01A0 */ f32 zFar;
|
||||
/* 0x01A4 */ f32 scale;
|
||||
/* 0x01A8 */ char unk_01A8[0x0010];
|
||||
/* 0x01B8 */ Vec3f eye;
|
||||
/* 0x01C4 */ Vec3f at;
|
||||
/* 0x01D0 */ Vec3f up;
|
||||
/* 0x01DC */ char unk_01DC[0x0150];
|
||||
/* 0x032C */ Vec3f distortionOrientation;
|
||||
/* 0x0338 */ Vec3f distortionScale;
|
||||
/* 0x0344 */ char unk_0344[0x0018];
|
||||
/* 0x035C */ f32 distortionSpeed;
|
||||
/* 0x0360 */ char unk_0360[0x0004];
|
||||
} view;
|
||||
/* 0x0364 */ Camera mainCamera;
|
||||
/* 0x0520 */ Camera subCameras[3];
|
||||
/* 0x0A54 */ Camera* cameraPtrs[4];
|
||||
/* 0x0A64 */ s16 activeCamera;
|
||||
/* 0x0A66 */ char unk_A66[0x0032];
|
||||
/* 0x0A98 */ CollisionContext colCtx;
|
||||
/* 0x208C */ ActorContext actorCtx;
|
||||
/* 0x2264 */ char unk_2264[0x0034];
|
||||
/* 0x2298 */ CutsceneContext csCtx; // "demo_play"
|
||||
/* 0x2304 */ char unk_2304[0x078C];
|
||||
/* 0x2A90 */ u8 msgMode; // seems to be used primarily for the ocarina
|
||||
/* 0x2A91 */ char unk_2A91[0xEB];
|
||||
/* 0x2B7C */ u16 lastPlayedSong;
|
||||
/* 0x2B7E */ s16 unk_2B7E; // msgCtx.unk_E3EE in OoT
|
||||
/* 0x2B80 */ char unk_2B80[0x06B0];
|
||||
/* 0x3230 */ u32 lightSettingsList_addr;
|
||||
/* 0x3234 */ char unk_3234[0x0824];
|
||||
/* 0x3A58 */ ObjectContext objectCtx;
|
||||
/* 0x43DC */ char unk_43DC[0x0854];
|
||||
/* 0x4C30 */ u8 roomNum;
|
||||
/* 0x4C31 */ char unk_4C31[0x0FCF];
|
||||
/* 0x5C00 */ u8 linkAgeOnLoad;
|
||||
/* 0x5C01 */ u8 unk_5C01;
|
||||
/* 0x5C02 */ u8 curSpawn;
|
||||
/* 0x5C03 */ char unk_5C03[0x0006];
|
||||
/* 0x5C09 */ ActorEntry* linkActorEntry;
|
||||
/* 0x5C0D */ char unk_5C0D[0x0008];
|
||||
/* 0x5C19 */ EntranceEntry* setupEntranceList;
|
||||
/* 0x5C1C */ s16* setupExitList;
|
||||
/* 0x5C20 */ char unk_5C20[0x000D];
|
||||
/* 0x5C2D */ s8 sceneLoadFlag; // "fade_direction"
|
||||
/* 0x5C2E */ char unk_5C2E[0x0004];
|
||||
/* 0x5C32 */ s16 nextEntranceIndex;
|
||||
/* 0x5C34 */ char unk_5C34[0x0042];
|
||||
/* 0x5C76 */ u8 fadeOutTransition;
|
||||
/* 0x5C78 */ CollisionCheckContext colChkCtx;
|
||||
// TODO
|
||||
} GlobalContext; // size = 0x5F14 TODO
|
||||
_Static_assert(sizeof(GlobalContext) == 0x5F14, "Global Context size");
|
||||
|
||||
typedef struct StaticContext {
|
||||
/* 0x0000 */ char unk_0[0x0D38];
|
||||
/* 0x0D38 */ s16 dekuNutFlash; // set to -1 to trigger flash
|
||||
/* 0x0D3A */ char unk_D3A[0x0126];
|
||||
/* 0x0E60 */ u16 spawnOnEpona;
|
||||
/* 0x0E62 */ char unk_E72[0x0010];
|
||||
/* 0x0E72 */ u16 collisionDisplay;
|
||||
/* 0x0E74 */ char unk_E74[0x015C];
|
||||
/* 0x0FD0 */ u16 renderGeometryDisable;
|
||||
/* 0x0FD2 */ char unk_FD2[0x0602];
|
||||
} StaticContext; // size 0x15D4
|
||||
// _Static_assert(sizeof(StaticContext) == 0x15D4, "Static Context size");
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s8 scene;
|
||||
/* 0x01 */ s8 spawn;
|
||||
/* 0x02 */ u16 field;
|
||||
} EntranceInfo; // size = 0x4
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ char infoFilename[0x44];
|
||||
/* 0x44 */ char filename[0x44];
|
||||
/* 0x88 */ char unk_88[0x01];
|
||||
/* 0x89 */ u8 config;
|
||||
/* 0x8A */ char unk_8A[0x02];
|
||||
} Scene; // size = 0x8C
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s16 objectId;
|
||||
/* 0x02 */ u8 objectModelIdx;
|
||||
/* 0x03 */ char unk_03[0x3];
|
||||
} DrawItemTableEntry;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u8 scene;
|
||||
/* 0x01 */ u8 flags1;
|
||||
/* 0x02 */ u8 flags2;
|
||||
/* 0x03 */ u8 flags3;
|
||||
} RestrictionFlags;
|
||||
|
||||
typedef struct TargetIndicatorModels {
|
||||
/* 0x00 */ SkeletonAnimationModel* pointer; // arrow above targetable actor
|
||||
/* 0x04 */ SkeletonAnimationModel* reticle[4]; // four arrows circling around target
|
||||
/* 0x14 */ SkeletonAnimationModel* reticleAfterimageOne[4]; // four arrows trailing behind `reticle`
|
||||
/* 0x24 */ SkeletonAnimationModel* reticleAfterimageTwo[4]; // four arrows trailing behind `reticleAfterimageOne`
|
||||
} TargetIndicatorModels;
|
||||
|
||||
typedef struct TargetContext {
|
||||
/* 0x000 */ char unk_000[0x4E];
|
||||
/* 0x04E */ u8 reticleActorType;
|
||||
/* 0x04F */ char unk_04F[0x61];
|
||||
/* 0x0B0 */ TargetIndicatorModels visibleTargetIndicators; // culled when behind a wall
|
||||
/* 0x0E4 */ TargetIndicatorModels hiddenTargetIndicators; // drawn even when behind walls
|
||||
/* 0x118 */ char unk_118[0x08];
|
||||
/* 0x120 */ ZARInfo* zarInfo;
|
||||
/* 0x124 */ char unk_120[0x04];
|
||||
/* 0x128 */ u32 pointerActorType;
|
||||
// ... size unknown
|
||||
} TargetContext;
|
||||
|
||||
extern GlobalContext* gGlobalContext;
|
||||
extern const u32 ItemSlots[];
|
||||
extern const char DungeonNames[][25];
|
||||
#define gSaveContext (*(SaveContext*)0x00587958)
|
||||
#define gStaticContext (*(StaticContext*)0x08080010)
|
||||
#define gObjectTable ((ObjectFile*)0x53CCF4)
|
||||
#define gEntranceTable ((EntranceInfo*)0x543BB8)
|
||||
#define gItemUsabilityTable ((u8*)0x506C58)
|
||||
#define gGearUsabilityTable ((u32*)0x4D47C8)
|
||||
#define gDungeonSceneTable ((Scene*)0x4DC400)
|
||||
#define gMQDungeonSceneTable ((Scene*)0x4DCBA8)
|
||||
#define gSceneTable ((Scene*)0x545484)
|
||||
#define gRandInt (*(u32*)0x50C0C4)
|
||||
#define gRandFloat (*(f32*)0x50C0C8)
|
||||
#define gDrawItemTable ((DrawItemTableEntry*)0x4D88C8)
|
||||
#define gRestrictionFlags ((RestrictionFlags*)0x539DC4)
|
||||
#define PLAYER ((Player*)gGlobalContext->actorCtx.actorList[ACTORTYPE_PLAYER].first)
|
||||
|
||||
#define GearSlot(X) (X - ITEM_SWORD_KOKIRI)
|
||||
|
||||
typedef enum {
|
||||
DUNGEON_DEKU_TREE = 0,
|
||||
DUNGEON_DODONGOS_CAVERN,
|
||||
DUNGEON_JABUJABUS_BELLY,
|
||||
DUNGEON_FOREST_TEMPLE,
|
||||
DUNGEON_FIRE_TEMPLE,
|
||||
DUNGEON_WATER_TEMPLE,
|
||||
DUNGEON_SPIRIT_TEMPLE,
|
||||
DUNGEON_SHADOW_TEMPLE,
|
||||
DUNGEON_BOTTOM_OF_THE_WELL,
|
||||
DUNGEON_ICE_CAVERN,
|
||||
DUNGEON_GANONS_TOWER,
|
||||
DUNGEON_GERUDO_TRAINING_GROUNDS,
|
||||
DUNGEON_THIEVES_HIDEOUT,
|
||||
DUNGEON_INSIDE_GANONS_CASTLE,
|
||||
DUNGEON_GANONS_TOWER_COLLAPSING_INTERIOR,
|
||||
DUNGEON_GANONS_CASTLE_COLLAPSING,
|
||||
DUNGEON_TREASURE_CHEST_SHOP,
|
||||
DUNGEON_DEKU_TREE_BOSS_ROOM,
|
||||
DUNGEON_DODONGOS_CAVERN_BOSS_ROOM,
|
||||
DUNGEON_JABUJABUS_BELLY_BOSS_ROOM,
|
||||
DUNGEON_FOREST_TEMPLE_BOSS_ROOM,
|
||||
DUNGEON_FIRE_TEMPLE_BOSS_ROOM,
|
||||
DUNGEON_WATER_TEMPLE_BOSS_ROOM,
|
||||
DUNGEON_SPIRIT_TEMPLE_BOSS_ROOM,
|
||||
DUNGEON_SHADOW_TEMPLE_BOSS_ROOM,
|
||||
} DungeonId;
|
||||
|
||||
#define SCENE_LINK_HOUSE 52
|
||||
|
||||
/* TODO: figure out what to do with this stuff */
|
||||
#define real_hid_addr 0x10002000
|
||||
#define real_hid (*(hid_mem_t*)real_hid_addr)
|
||||
|
||||
#define Z3D_TOP_SCREEN_LEFT_1 0x14313890
|
||||
#define Z3D_TOP_SCREEN_LEFT_2 0x14359DA0
|
||||
#define Z3D_TOP_SCREEN_RIGHT_1 0x14410AD0
|
||||
#define Z3D_TOP_SCREEN_RIGHT_2 0x14456FE0
|
||||
#define Z3D_BOTTOM_SCREEN_1 0x143A02B0
|
||||
#define Z3D_BOTTOM_SCREEN_2 0x143D86C0
|
||||
|
||||
typedef void (*Item_Give_proc)(GlobalContext* globalCtx, u8 item);
|
||||
#define Item_Give_addr 0x376A78
|
||||
#define Item_Give ((Item_Give_proc)Item_Give_addr)
|
||||
|
||||
typedef void (*DisplayTextbox_proc)(GlobalContext* globalCtx, u16 textId, Actor* actor);
|
||||
#define DisplayTextbox_addr 0x367C7C
|
||||
#define DisplayTextbox ((DisplayTextbox_proc)DisplayTextbox_addr)
|
||||
|
||||
typedef u32 (*EventCheck_proc)(u32 flag);
|
||||
#define EventCheck_addr 0x350CF4
|
||||
#define EventCheck ((EventCheck_proc)EventCheck_addr)
|
||||
|
||||
typedef void (*EventSet_proc)(u32 flag);
|
||||
#define EventSet_addr 0x34CBF8
|
||||
#define EventSet ((EventSet_proc)EventSet_addr)
|
||||
|
||||
typedef void (*Rupees_ChangeBy_proc)(s16 rupeeChange);
|
||||
#define Rupees_ChangeBy_addr 0x376A60
|
||||
#define Rupees_ChangeBy ((Rupees_ChangeBy_proc)Rupees_ChangeBy_addr)
|
||||
|
||||
typedef void (*LinkDamage_proc)(GlobalContext* globalCtx, Player* player, s32 arg2, f32 arg3, f32 arg4, s16 arg5,
|
||||
s32 arg6);
|
||||
#define LinkDamage_addr 0x35D304
|
||||
#define LinkDamage ((LinkDamage_proc)LinkDamage_addr)
|
||||
|
||||
typedef u32 (*Inventory_HasEmptyBottle_proc)(void);
|
||||
#define Inventory_HasEmptyBottle_addr 0x377A04
|
||||
#define Inventory_HasEmptyBottle ((Inventory_HasEmptyBottle_proc)Inventory_HasEmptyBottle_addr)
|
||||
|
||||
typedef void (*PlaySound_proc)(u32);
|
||||
#define PlaySound_addr 0x35C528
|
||||
// This function plays sound effects and music tracks, overlaid on top of the current BGM
|
||||
#define PlaySound ((PlaySound_proc)PlaySound_addr)
|
||||
|
||||
typedef Actor* (*Actor_Spawn_proc)(ActorContext* actorCtx, GlobalContext* globalCtx, s16 actorId, float posX,
|
||||
float posY, float posZ, s16 rotX, s16 rotY, s16 rotZ, s16 params)
|
||||
__attribute__((pcs("aapcs-vfp")));
|
||||
#define Actor_Spawn_addr 0x3738D0
|
||||
#define Actor_Spawn ((Actor_Spawn_proc)Actor_Spawn_addr)
|
||||
|
||||
typedef Actor* (*Actor_Find_proc)(ActorContext* actorCtx, s16 actorId, u8 actorType);
|
||||
#define Actor_Find_addr 0x372D64
|
||||
#define Actor_Find ((Actor_Find_proc)Actor_Find_addr)
|
||||
|
||||
typedef void (*Actor_GetScreenPos_proc)(GlobalContext* globalCtx, Actor* actor, s16* outX, s16* outY);
|
||||
#define Actor_GetScreenPos_addr 0x363A20
|
||||
#define Actor_GetScreenPos ((Actor_GetScreenPos_proc)Actor_GetScreenPos_addr)
|
||||
|
||||
typedef void (*FireDamage_proc)(Actor* player, GlobalContext* globalCtx, int flamesColor);
|
||||
#define FireDamage_addr 0x35D8D8
|
||||
#define FireDamage ((FireDamage_proc)FireDamage_addr)
|
||||
|
||||
typedef void (*Flags_SetEnv_proc)(GlobalContext* globalCtx, s16 flag);
|
||||
#define Flags_SetEnv_addr 0x366704
|
||||
#define Flags_SetEnv ((Flags_SetEnv_proc)Flags_SetEnv_addr)
|
||||
|
||||
typedef void (*GiveItem_proc)(Actor* actor, GlobalContext* globalCtx, s32 getItemId, f32 xzRange, f32 yRange)
|
||||
__attribute__((pcs("aapcs-vfp")));
|
||||
#define GiveItem_addr 0x3724DC
|
||||
#define GiveItem ((GiveItem_proc)GiveItem_addr)
|
||||
|
||||
typedef void (*Message_CloseTextbox_proc)(GlobalContext* globalCtx);
|
||||
#define Message_CloseTextbox_addr 0x3725E0
|
||||
#define Message_CloseTextbox ((Message_CloseTextbox_proc)Message_CloseTextbox_addr)
|
||||
|
||||
typedef void (*SetupItemInWater_proc)(Player* player, GlobalContext* globalCtx);
|
||||
#define SetupItemInWater_addr 0x354894
|
||||
#define SetupItemInWater ((SetupItemInWater_proc)SetupItemInWater_addr)
|
||||
|
||||
typedef void (*Health_ChangeBy_proc)(GlobalContext* arg1, u32 arg2);
|
||||
#define Health_ChangeBy_addr 0x352DBC
|
||||
#define Health_ChangeBy ((Health_ChangeBy_proc)Health_ChangeBy_addr)
|
||||
|
||||
typedef void (*PlaySFX_proc)(u32 sfxId, Vec3f* pos, u32 token, f32* freqScale, f32* a4, s8* reverbAdd);
|
||||
#define PlaySFX_addr 0x37547C
|
||||
#define PlaySFX ((PlaySFX_proc)PlaySFX_addr)
|
||||
|
||||
typedef void (*Flags_SetSwitch_proc)(GlobalContext* globalCtx, u32 flag);
|
||||
#define Flags_SetSwitch_addr 0x375C10
|
||||
#define Flags_SetSwitch ((Flags_SetSwitch_proc)Flags_SetSwitch_addr)
|
||||
|
||||
typedef u32 (*Flags_GetSwitch_proc)(GlobalContext* globalCtx, u32 flag);
|
||||
#define Flags_GetSwitch_addr 0x36E864
|
||||
#define Flags_GetSwitch ((Flags_GetSwitch_proc)Flags_GetSwitch_addr)
|
||||
|
||||
typedef u32 (*Flags_GetCollectible_proc)(GlobalContext* globalCtx, u32 flag);
|
||||
#define Flags_GetCollectible_addr 0x36405C
|
||||
#define Flags_GetCollectible ((Flags_GetCollectible_proc)Flags_GetCollectible_addr)
|
||||
|
||||
typedef void (*Player_SetEquipmentData_proc)(GlobalContext* globalCtx, Player* player);
|
||||
#define Player_SetEquipmentData_addr 0x34913C
|
||||
#define Player_SetEquipmentData ((Player_SetEquipmentData_proc)Player_SetEquipmentData_addr)
|
||||
|
||||
typedef s32 (*BossChallenge_IsActive_proc)(void);
|
||||
#define BossChallenge_IsActive_addr 0x35B164
|
||||
#define BossChallenge_IsActive ((BossChallenge_IsActive_proc)BossChallenge_IsActive_addr)
|
||||
|
||||
typedef s32 (*Audio_PlayActorSfx2_proc)(Actor* actor, s32 sfxID);
|
||||
#define Audio_PlayActorSfx2_addr 0x375BCC
|
||||
#define Audio_PlayActorSfx2 ((Audio_PlayActorSfx2_proc)Audio_PlayActorSfx2_addr)
|
||||
|
||||
typedef void (*Model_EnableMeshGroupByIndex_proc)(SkeletonAnimationModel* skel, u32 index);
|
||||
#define Model_EnableMeshGroupByIndex ((Model_EnableMeshGroupByIndex_proc)0x37266C)
|
||||
|
||||
typedef void (*Model_DisableMeshGroupByIndex_proc)(SkeletonAnimationModel* skel, u32 index);
|
||||
#define Model_DisableMeshGroupByIndex ((Model_DisableMeshGroupByIndex_proc)0x36932C)
|
||||
|
||||
typedef s32 (*Player_InBlockingCsMode_proc)(GlobalContext* globalCtx, Player* player);
|
||||
#define Player_InBlockingCsMode ((Player_InBlockingCsMode_proc)0x35DB20)
|
||||
|
||||
typedef s32 (*Camera_CheckWater_proc)(Camera* camera);
|
||||
#define Camera_CheckWater ((Camera_CheckWater_proc)0x2D06A0)
|
||||
|
||||
typedef void (*Camera_UpdateInterface_proc)(u32 flags);
|
||||
#define Camera_UpdateInterface ((Camera_UpdateInterface_proc)0x330D84)
|
||||
|
||||
typedef f32 (*Camera_BGCheckInfo_proc)(Camera* camera, Vec3f* from, CamColChk* to);
|
||||
#define Camera_BGCheckInfo ((Camera_BGCheckInfo_proc)0x3553FC)
|
||||
|
||||
typedef s32 (*Quake_Update_proc)(Camera* camera, ShakeInfo* camShake);
|
||||
#ifdef Version_EUR
|
||||
#define Quake_Update_addr 0x4787E8
|
||||
#else
|
||||
#define Quake_Update_addr 0x4787C8
|
||||
#endif
|
||||
#define Quake_Update ((Quake_Update_proc)Quake_Update_addr)
|
||||
|
||||
typedef s16 (*Camera_GetCamDataId_proc)(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId);
|
||||
#ifdef Version_EUR
|
||||
#define Camera_GetCamDataId_addr 0x47BFF8
|
||||
#else
|
||||
#define Camera_GetCamDataId_addr 0x47BFD8
|
||||
#endif
|
||||
#define Camera_GetCamDataId ((Camera_GetCamDataId_proc)Camera_GetCamDataId_addr)
|
||||
|
||||
#endif //_Z3D_H_
|
350
include/z3D/z3Dactor.h
Normal file
350
include/z3D/z3Dactor.h
Normal file
@@ -0,0 +1,350 @@
|
||||
#ifndef _Z3DACTOR_H_
|
||||
#define _Z3DACTOR_H_
|
||||
|
||||
#include "z3Dvec.h"
|
||||
|
||||
struct Actor;
|
||||
struct GlobalContext;
|
||||
|
||||
struct LightMapper;
|
||||
struct ZARInfo;
|
||||
|
||||
typedef struct {
|
||||
Vec3f pos;
|
||||
Vec3s rot;
|
||||
} PosRot; // size = 0x14
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ char unk_00[0x8];
|
||||
/* 0x08 */ Vec3s norm; // Normal vector
|
||||
/* 0x0E */ s16 dist; // Plane distance from origin
|
||||
} CollisionPoly; // size = 0x10
|
||||
|
||||
struct SkeletonAnimationModel;
|
||||
typedef void (*SkeletonAnimationModelFunc)(struct SkeletonAnimationModel*);
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ char unk_00[0x4];
|
||||
/* 0x04 */ SkeletonAnimationModelFunc destroy;
|
||||
} SkeletonAnimationModel_VTable;
|
||||
|
||||
typedef struct SkeletonAnimationModel_unk_10 {
|
||||
/* 0x00 */ char unk_00[0x14];
|
||||
} SkeletonAnimationModel_unk_10; // size = 0x14
|
||||
|
||||
typedef struct SkeletonAnimationModel_unk_0C {
|
||||
/* 0x00 */ SkeletonAnimationModel_unk_10* unk_00;
|
||||
/* 0x04 */ void* cmabManager;
|
||||
/* 0x08 */ f32 curFrame;
|
||||
/* 0x0C */ f32 animSpeed;
|
||||
/* 0x10 */ s8 animMode;
|
||||
/* 0x11 */ char unk_11[0x87];
|
||||
} SkeletonAnimationModel_unk_0C; // size = 0x98
|
||||
|
||||
typedef struct SkeletonAnimationModel {
|
||||
/* 0x00 */ SkeletonAnimationModel_VTable* vtbl;
|
||||
/* 0x04 */ char unk_04[0x08];
|
||||
/* 0x0C */ SkeletonAnimationModel_unk_0C* unk_0C;
|
||||
/* 0x10 */ SkeletonAnimationModel_unk_10* unk_10;
|
||||
/* 0x14 */ void* unk_draw_struct_14;
|
||||
/* 0x18 */ char unk_18[0x64];
|
||||
/* 0x7C */ nn_math_MTX34 mtx;
|
||||
/* 0xAC */ s8 unk_AC;
|
||||
/* 0xAD */ char unk_AD[0x03];
|
||||
} SkeletonAnimationModel; // size = 0xB0
|
||||
|
||||
typedef struct SkelAnime {
|
||||
/* 0x00 */ void* unk_00;
|
||||
/* 0x04 */ struct ZARInfo* zarInfo;
|
||||
/* 0x08 */ char unk_08[0x08];
|
||||
/* 0x10 */ struct GlobalContext* globalCtx;
|
||||
/* 0x14 */ char unk_14[0x14];
|
||||
/* 0x28 */ struct SkeletonAnimationModel* unk_28;
|
||||
/* 0x2C */ char unk_2C[0x4];
|
||||
/* 0x30 */ s32 animationType;
|
||||
/* 0x34 */ char unk_34[0x8];
|
||||
/* 0x3C */ f32 curFrame;
|
||||
/* 0x40 */ f32 playSpeed;
|
||||
/* 0x44 */ f32 startFrame;
|
||||
/* 0x48 */ f32 endFrame;
|
||||
/* 0x4C */ f32 animLength;
|
||||
/* 0x50 */ char unk_50[0x24];
|
||||
/* 0x74 */ u8 limbCount;
|
||||
/* 0x75 */ char unk_75[0x03];
|
||||
/* 0x78 */ void* jointTable;
|
||||
/* 0x7C */ void* morphTable;
|
||||
/* 0x80 */ char unk_80[0x02];
|
||||
/* 0x82 */ u8 tablesAllocated;
|
||||
/* 0x83 */ char unk_83[0x01];
|
||||
} SkelAnime; // size = 0x84
|
||||
|
||||
typedef void (*ActorFunc)(struct Actor*, struct GlobalContext*);
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s16 id;
|
||||
/* 0x02 */ u8 type; // Classifies actor and determines when actor will execute
|
||||
/* 0x03 */ u8 room; // Room instance was spawned in. If value set to FF in rom,
|
||||
// instance does not despawn when swapping rooms
|
||||
/* 0x04 */ u32 flags;
|
||||
/* 0x08 */ s16 objectId;
|
||||
/* 0x0C */ u32 instanceSize;
|
||||
/* 0x10 */ ActorFunc init; // Constructor
|
||||
/* 0x14 */ ActorFunc destroy; // Destructor
|
||||
/* 0x18 */ ActorFunc update; // Main Update Function
|
||||
/* 0x1C */ ActorFunc draw; // Draw function
|
||||
} ActorInit; // size = 0x20
|
||||
|
||||
typedef enum {
|
||||
ALLOCTYPE_NORMAL,
|
||||
ALLOCTYPE_ABSOLUTE,
|
||||
ALLOCTYPE_PERMANENT
|
||||
} AllocType;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u32 vromStart; // unused?
|
||||
/* 0x04 */ u32 vromEnd; // unused?
|
||||
/* 0x08 */ void* vramStart; // unused?
|
||||
/* 0x0C */ void* vramEnd; // unused?
|
||||
/* 0x10 */ void* loadedRamAddr; // unused?
|
||||
/* 0x14 */ ActorInit* initInfo;
|
||||
/* 0x18 */ char* name; // unused?
|
||||
/* 0x1C */ u16 allocType; // unused?
|
||||
/* 0x1E */ s8 nbLoaded; // unused?
|
||||
} ActorOverlay; // size = 0x20
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
char damage : 4;
|
||||
char effect : 4;
|
||||
} attack[32];
|
||||
} ActorDamageChart;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ ActorDamageChart* damageChart; // For actors which contain a damage chart (example: Stalfos)...
|
||||
/* 0x04 */ Vec3f displacement; // Amount to correct velocity (0x5C) by when colliding into a body
|
||||
/* 0x10 */ s16 unk_10;
|
||||
/* 0x12 */ s16 unk_12;
|
||||
/* 0x14 */ u16 unk_14;
|
||||
/* 0x16 */ u8 mass; // Used to compute displacement, 50 is common value, 0xFF for infinite mass/unmoveable
|
||||
/* 0x17 */ u8 health;
|
||||
/* 0x18 */ u8 damage; // Amount to decrement health by
|
||||
/* 0x19 */ u8 damageEffect; // Stores what effect should occur when hit by a weapon
|
||||
/* 0x1A */ u8 atHitEffect;
|
||||
/* 0x1B */ u8 acHitEffect;
|
||||
} CollisionCheckInfo; // size = 0x1C
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ struct Actor* actor; // Attached actor
|
||||
/* 0x04 */ struct Actor* at; // Actor attached to what it collided with as an AT collider.
|
||||
/* 0x08 */ struct Actor* ac; // Actor attached to what it collided with as an AC collider.
|
||||
/* 0x0C */ struct Actor* oc; // Actor attached to what it collided with as an OC collider.
|
||||
/* 0x10 */ u8 atFlags; // Information flags for AT collisions.
|
||||
/* 0x11 */ u8 acFlags; // Information flags for AC collisions.
|
||||
/* 0x12 */ u8 ocFlags1; // Information flags for OC collisions.
|
||||
/* 0x13 */ u8 ocFlags2; // Flags related to which colliders it can OC collide with.
|
||||
/* 0x14 */ u8 colType; // Determines hitmarks and sound effects during AC collisions.
|
||||
/* 0x15 */ u8 shape; // JntSph, Cylinder, Tris, or Quad
|
||||
} Collider; // size = 0x18
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ Collider base;
|
||||
/* 0x18 */ // ColliderInfo info;
|
||||
/* 0x40 */ // Cylinderf dim;
|
||||
} ColliderCylinder; // size = 0x58
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ Vec3s rot; // Current actor shape rotation
|
||||
/* 0x06 */ u8 unk_06;
|
||||
/* 0x08 */ f32 unk_08; // Model y axis offset. Represents model space units. collision mesh related
|
||||
/* 0x0C */ void (*shadowDrawFunc)(struct Actor*, struct LightMapper*, struct GlobalContext*);
|
||||
/* 0x10 */ f32 unk_10;
|
||||
/* 0x14 */ u8 unk_14;
|
||||
/* 0x15 */ u8 unk_15;
|
||||
} ActorShape; // size = 0x18
|
||||
|
||||
typedef struct Actor {
|
||||
/* 0x000 */ s16 id; // Actor Id
|
||||
/* 0x002 */ u8 type; // Actor Type. Refer to the corresponding enum for values
|
||||
/* 0x003 */ s8 room; // Room number the actor is in. -1 denotes that the actor won't despawn on a room change
|
||||
/* 0x004 */ u32 flags; // Flags used for various purposes
|
||||
/* 0x008 */ PosRot home; // Initial position/rotation when spawned. Can be used for other purposes
|
||||
/* 0x01C */ s16 params; // Configurable variable set by the actor's spawn data; original name: "args_data"
|
||||
/* 0x01E */ s8 objBankIndex; // Object bank index of the actor's object dependency; original name: "bank"
|
||||
/* 0x01F */ s8 targetMode; // Controls how far the actor can be targeted from and how far it can stay locked on
|
||||
/* 0x020 */ u8 unk_20;
|
||||
/* 0x021 */ char unk_21[0x3];
|
||||
/* 0x024 */ u32 sfx; // SFX ID to play. Sound plays when value is set, then is cleared the following update cycle
|
||||
/* 0x028 */ PosRot world; // Position/rotation in the world
|
||||
/* 0x03C */ PosRot focus; // Target reticle focuses on this position. For player this represents head pos and rot
|
||||
/* 0x050 */ f32 targetArrowOffset; // Height offset of the target arrow relative to `focus` position
|
||||
/* 0x054 */ Vec3f scale; // Scale of the actor in each axis
|
||||
/* 0x060 */ Vec3f velocity; // Velocity of the actor in each axis
|
||||
/* 0x06C */ f32 speedXZ; // How fast the actor is traveling along the XZ plane
|
||||
/* 0x070 */ f32 gravity; // Acceleration due to gravity. Value is added to Y velocity every frame
|
||||
/* 0x074 */ f32 minVelocityY; // Sets the lower bounds cap on velocity along the Y axis
|
||||
/* 0x078 */ CollisionPoly* wallPoly; // Wall polygon an actor is touching
|
||||
/* 0x07C */ CollisionPoly* floorPoly; // Floor polygon directly below the actor
|
||||
/* 0x080 */ u8 wallBgId; // Bg ID of the wall polygon the actor is touching
|
||||
/* 0x081 */ u8 floorBgId; // Bg ID of the floor polygon directly below the actor
|
||||
/* 0x082 */ s16 wallYaw; // Y rotation of the wall polygon the actor is touching
|
||||
/* 0x084 */ f32 floorHeight; // Y position of the floor polygon directly below the actor
|
||||
/* 0x088 */ f32 yDistToWater; // Distance to the surface of active waterbox. Negative value means above water
|
||||
/* 0x08C */ f32 waterBoxYSurface;
|
||||
/* 0x090 */ u16 bgCheckFlags;
|
||||
/* 0x092 */ s16 yawTowardsPlayer; // Y rotation difference between the actor and the player
|
||||
/* 0x094 */ f32 xyzDistToPlayerSq; // Squared distance between the actor and the player in the x,y,z axis
|
||||
/* 0x098 */ f32 xzDistToPlayer; // Distance between the actor and the player in the XZ plane
|
||||
/* 0x09C */ f32 yDistToPlayer; // Dist is negative if the actor is above the player
|
||||
/* 0x0A0 */ CollisionCheckInfo colChkInfo; // Variables related to the Collision Check system
|
||||
/* 0x0BC */ ActorShape shape; // Variables related to the physical shape of the actor
|
||||
/* 0x0D4 */ Vec3f unk_D4[2];
|
||||
/* 0x0EC */ Vec3f unk_EC; // Stores result of some vector transformation involving actor xyz vector, and a matrix at
|
||||
// Global Context + 11D60
|
||||
/* 0x0F8 */ f32 unk_F8; // Related to above
|
||||
/* 0x0FC */ f32 uncullZoneForward; // Amount to increase the uncull zone forward by (in projected space)
|
||||
/* 0x100 */ f32 uncullZoneScale; // Amount to increase the uncull zone scale by (in projected space)
|
||||
/* 0x104 */ f32 uncullZoneDownward; // Amount to increase uncull zone downward by (in projected space)
|
||||
/* 0x108 */ Vec3f prevPos; // World position from the previous update cycle
|
||||
/* 0x114 */ u8 isTargeted; // Set to true if the actor is currently being targeted by the player
|
||||
/* 0x115 */ u8 targetPriority; // Lower values have higher priority. Resets to 0 when player stops targeting
|
||||
/* 0x116 */ u16 textId; // Text ID to pass to link/display when interacting with the actor
|
||||
/* 0x118 */ u16 freezeTimer; // Actor does not update when set. Timer decrements automatically
|
||||
/* 0x11A */ s16 colorFilterTimer;
|
||||
/* 0x11C */ u32 colorFilterParams;
|
||||
/* 0x120 */ char unk_120;
|
||||
/* 0x121 */ u8 isDrawn; // Set to true if the actor is currently being drawn. Always stays false for lens actors
|
||||
/* 0x122 */ u8 unk_122; // Set within a routine that deals with collision
|
||||
/* 0x123 */ u8 naviEnemyId; // Sets what 0600 dialog to display when talking to navi. Default 0xFF
|
||||
/* 0x124 */ struct Actor* parent; // Usage is actor specific. Set if actor is spawned via `Actor_SpawnAsChild`
|
||||
/* 0x128 */ struct Actor* child; // Usage is actor specific. Set if actor is spawned via `Actor_SpawnAsChild`
|
||||
/* 0x12C */ struct Actor* prev; // Previous actor of this category
|
||||
/* 0x130 */ struct Actor* next; // Next actor of this category
|
||||
/* 0x134 */ ActorFunc init; // Initialization Routine. Called by `Actor_Init` or `Actor_UpdateAll`
|
||||
/* 0x138 */ ActorFunc destroy; // Destruction Routine. Called by `Actor_Destroy`
|
||||
/* 0x13C */ ActorFunc update; // Update Routine. Called by `Actor_UpdateAll`
|
||||
/* 0x140 */ ActorFunc draw; // Draw Routine. Called by `Actor_Draw`
|
||||
/* 0x144 */ ActorOverlay* overlayEntry; // Pointer to the overlay table entry for this actor
|
||||
/* 0x148 */ nn_math_MTX34 modelMtx; // Transforms model space coordinates to world coordinates
|
||||
/* 0x178 */ void* unk_178; // Unknown pointer type
|
||||
/* 0x17C */ void* unk_17C[6]; // Unknown pointer type
|
||||
/* 0x194 */ u32 unk_194;
|
||||
/* 0x198 */ u8 unk_198;
|
||||
/* 0x199 */ char unk_199[0x3];
|
||||
/* 0x19C */ u16 unk_19C;
|
||||
/* 0x19E */ char unk_19E[0x2];
|
||||
/* 0x1A0 */ f32 unk_1A0;
|
||||
/* From here on, the structure and size varies for each actor */
|
||||
} Actor; // size = 0x1A4
|
||||
|
||||
typedef struct DynaPolyActor {
|
||||
/* 0x000 */ struct Actor actor;
|
||||
/* 0x1A4 */ s32 bgId;
|
||||
/* 0x1A8 */ f32 unk_1A8;
|
||||
/* 0x1AC */ f32 unk_1AC;
|
||||
/* 0x1B0 */ s16 unk_1B0;
|
||||
/* 0x1B2 */ u16 unk_1B2;
|
||||
/* 0x1B4 */ u32 unk_1B4;
|
||||
/* 0x1B8 */ u8 unk_1B8;
|
||||
/* 0x1BA */ s16 unk_1BA;
|
||||
} DynaPolyActor; // size = 0x1BC
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ Actor* actor;
|
||||
/* 0x04 */ char unk_04[0x10];
|
||||
/* 0x14 */ Vec3f scale1;
|
||||
/* 0x20 */ Vec3s rot1;
|
||||
/* 0x28 */ Vec3f pos1;
|
||||
/* 0x34 */ Vec3f scale2;
|
||||
/* 0x40 */ Vec3s rot2;
|
||||
/* 0x48 */ Vec3f pos2;
|
||||
/* 0x54 */ char unk_54[0x18];
|
||||
} ActorMesh; // size = 0x6C
|
||||
|
||||
typedef struct {
|
||||
/* 0x0000 */ Actor actor;
|
||||
/* 0x01A4 */ char unk_148[0x0005];
|
||||
/* 0x01A9 */ s8 heldItemActionParam;
|
||||
/* 0x01AA */ u8 heldItemId;
|
||||
/* 0x01AB */ char unk_1AB[0x1];
|
||||
/* 0x01AC */ s8 itemActionParam;
|
||||
/* 0x01AD */ char unk_1AD[0x0003];
|
||||
/* 0x01B0 */ u8 modelGroup;
|
||||
/* 0x01B1 */ u8 nextModelGroup;
|
||||
/* 0x01B2 */ s8 unk_1B2;
|
||||
/* 0x01B3 */ u8 modelAnimType;
|
||||
/* 0x01B4 */ u8 leftHandType;
|
||||
/* 0x01B5 */ u8 rightHandType;
|
||||
/* 0x01B6 */ u8 sheathType;
|
||||
/* 0x01B7 */ u8 currentMask;
|
||||
/* 0x01B8 */ char unk_1B8[0x0004];
|
||||
/* 0x01BC */ void* rightHandDLists;
|
||||
/* 0x01C0 */ void* leftHandDLists;
|
||||
/* 0x01C4 */ void* sheathDLists;
|
||||
/* 0x01C8 */ void* waistDLists;
|
||||
/* 0x01CC */ char unk_1CC[0x80];
|
||||
/* 0x024C */ void* giDrawSpace;
|
||||
/* 0x0250 */ char unk_250[0x0004];
|
||||
/* 0x0254 */ struct SkelAnime skelAnime;
|
||||
/* 0x02D8 */ char unk_2D8[0x0F4C];
|
||||
/* 0x1224 */ Actor* heldActor;
|
||||
/* 0x1228 */ char unk_1228[0x84];
|
||||
/* 0x12AC */ u8 getItemId;
|
||||
/* 0x12AD */ char unk_12AD[0x0001];
|
||||
/* 0x12AE */ u16 getItemDirection;
|
||||
/* 0x12B0 */ Actor* interactRangeActor;
|
||||
/* 0x12B4 */ char unk_12B4[0x0454];
|
||||
/* 0x1708 */ void* stateFuncPtr;
|
||||
/* 0x170C */ char unk_170C[0x0004];
|
||||
/* 0x1710 */ u32 stateFlags1;
|
||||
/* 0x1714 */ u32 stateFlags2;
|
||||
/* 0x1718 */ Actor* unk_1718;
|
||||
/* 0x171C */ Actor* boomerangActor;
|
||||
/* 0x1720 */ Actor* unk_1720;
|
||||
/* 0x1724 */ Actor* naviActor;
|
||||
/* 0x1728 */ s16 naviTextId;
|
||||
/* 0x172A */ u8 stateFlags3;
|
||||
/* 0x172B */ s8 exchangeItemId;
|
||||
/* 0x172C */ char unk_172C[0x0AF0];
|
||||
/* 0x221C */ float xzSpeed; // probably
|
||||
/* 0x2220 */ char unk_2220[0x0007];
|
||||
/* 0x2227 */ s8 meleeWeaponState;
|
||||
/* 0x2228 */ char unk_2228[0x0020];
|
||||
/* 0x2248 */ s16 fishingState; // 1: casting line, 2: can reel, 3: holding catch
|
||||
/* 0x224A */ char unk_224A[0x023E];
|
||||
/* 0x2488 */ s8 invincibilityTimer; // prevents damage when nonzero
|
||||
// (positive = visible, counts towards zero each frame)
|
||||
/* 0x2489 */ char unk_2489[0x27B];
|
||||
/* 0x2704 */ struct SkeletonAnimationModel_unk_0C* bodyTexAnim;
|
||||
} Player; // total size (from init vars): 2A4C
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ ACTORTYPE_SWITCH,
|
||||
/* 0x01 */ ACTORTYPE_BG,
|
||||
/* 0x02 */ ACTORTYPE_PLAYER,
|
||||
/* 0x03 */ ACTORTYPE_EXPLOSIVES,
|
||||
/* 0x04 */ ACTORTYPE_NPC,
|
||||
/* 0x05 */ ACTORTYPE_ENEMY,
|
||||
/* 0x06 */ ACTORTYPE_PROP,
|
||||
/* 0x07 */ ACTORTYPE_ITEMACTION,
|
||||
/* 0x08 */ ACTORTYPE_MISC,
|
||||
/* 0x09 */ ACTORTYPE_BOSS,
|
||||
/* 0x0A */ ACTORTYPE_DOOR,
|
||||
/* 0x0B */ ACTORTYPE_CHEST
|
||||
} ActorType;
|
||||
|
||||
typedef struct ActorHeapNode {
|
||||
u16 magic;
|
||||
u16 free;
|
||||
u32 size;
|
||||
struct ActorHeapNode* next;
|
||||
struct ActorHeapNode* prev;
|
||||
} ActorHeapNode;
|
||||
|
||||
void Actor_Kill(Actor* actor);
|
||||
#define gActorOverlayTable ((ActorOverlay*)0x50CD84)
|
||||
|
||||
typedef u32 (*Actor_HasParent_proc)(Actor* actor, struct GlobalContext* globalCtx);
|
||||
#define Actor_HasParent_addr 0x371E40
|
||||
#define Actor_HasParent ((Actor_HasParent_proc)Actor_HasParent_addr)
|
||||
|
||||
#endif
|
46
include/z3D/z3Dcutscene.h
Normal file
46
include/z3D/z3Dcutscene.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _Z3DCUTSCENE_H_
|
||||
#define _Z3DCUTSCENE_H_
|
||||
|
||||
#include "z3Dvec.h"
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u16 action; // "dousa"
|
||||
/* 0x02 */ u16 startFrame;
|
||||
/* 0x04 */ u16 endFrame;
|
||||
/* 0x06 */ Vec3s rot;
|
||||
/* 0x0C */ Vec3i startPos;
|
||||
/* 0x18 */ Vec3i endPos;
|
||||
/* 0x24 */ Vec3i normal;
|
||||
} CsCmdActorAction; // size = 0x30
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ OCARINA_ACTION_UNK_0,
|
||||
/* 0x01 */ OCARINA_ACTION_FREE_PLAY_OCARINA,
|
||||
/* 0x02 */ OCARINA_ACTION_MINUET,
|
||||
/* 0x03 */ OCARINA_ACTION_BOLERO,
|
||||
/* 0x04 */ OCARINA_ACTION_SERENADE,
|
||||
/* 0x05 */ OCARINA_ACTION_REQUIEM,
|
||||
/* 0x06 */ OCARINA_ACTION_NOCTURNE,
|
||||
/* 0x07 */ OCARINA_ACTION_PRELUDE,
|
||||
/* 0x08 */ OCARINA_ACTION_SARIAS_SONG,
|
||||
/* 0x09 */ OCARINA_ACTION_EPONAS_SONG,
|
||||
/* 0x0A */ OCARINA_ACTION_ZELDAS_LULLABY,
|
||||
/* 0x0B */ OCARINA_ACTION_SUNS_SONG,
|
||||
/* 0x0C */ OCARINA_ACTION_SONG_OF_TIME,
|
||||
/* 0x0D */ OCARINA_ACTION_SONG_OF_STORMS,
|
||||
/* 0x0E */ OCARINA_ACTION_OCARINA_ACTION_UNK_E,
|
||||
/* 0x0F */ OCARINA_ACTION_MINUET_PLAYBACK,
|
||||
/* 0x10 */ OCARINA_ACTION_BOLERO_PLAYBACK,
|
||||
/* 0x11 */ OCARINA_ACTION_SERENADE_PLAYBACK,
|
||||
/* 0x12 */ OCARINA_ACTION_REQUIEM_PLAYBACK,
|
||||
/* 0013 */ OCARINA_ACTION_NOCTURNE_PLAYBACK,
|
||||
/* 0x14 */ OCARINA_ACTION_PRELUDE_PLAYBACK,
|
||||
/* 0x15 */ OCARINA_ACTION_SARIAS_SONG_PLAYBACK,
|
||||
/* 0x16 */ OCARINA_ACTION_EPONAS_SONG_PLAYBACK,
|
||||
/* 0x17 */ OCARINA_ACTION_ZELDAS_LULLABY_PLAYBACK,
|
||||
/* 0x18 */ OCARINA_ACTION_SUNS_SONG_PLAYBACK,
|
||||
/* 0x19 */ OCARINA_ACTION_SONG_OF_TIME_PLAYBACK,
|
||||
/* 0x1A */ OCARINA_ACTION_SONG_OF_STORMS_PLAYBACK
|
||||
} OcarinaSongActionIDs;
|
||||
|
||||
#endif //_Z3DCUTSCENE_H_
|
361
include/z3D/z3Ditem.h
Normal file
361
include/z3D/z3Ditem.h
Normal file
@@ -0,0 +1,361 @@
|
||||
#ifndef _Z3D_ITEM_H_
|
||||
#define _Z3D_ITEM_H_
|
||||
|
||||
#include "z3Dvec.h"
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ SLOT_STICK,
|
||||
/* 0x01 */ SLOT_NUT,
|
||||
/* 0x02 */ SLOT_BOMB,
|
||||
/* 0x03 */ SLOT_BOW,
|
||||
/* 0x04 */ SLOT_ARROW_FIRE,
|
||||
/* 0x05 */ SLOT_DINS_FIRE,
|
||||
/* 0x06 */ SLOT_SLINGSHOT,
|
||||
/* 0x07 */ SLOT_OCARINA,
|
||||
/* 0x08 */ SLOT_BOMBCHU,
|
||||
/* 0x09 */ SLOT_HOOKSHOT,
|
||||
/* 0x0A */ SLOT_ARROW_ICE,
|
||||
/* 0x0B */ SLOT_FARORES_WIND,
|
||||
/* 0x0C */ SLOT_BOOMERANG,
|
||||
/* 0x0D */ SLOT_LENS,
|
||||
/* 0x0E */ SLOT_BEAN,
|
||||
/* 0x0F */ SLOT_HAMMER,
|
||||
/* 0x10 */ SLOT_ARROW_LIGHT,
|
||||
/* 0x11 */ SLOT_NAYRUS_LOVE,
|
||||
/* 0x12 */ SLOT_BOTTLE_1,
|
||||
/* 0x13 */ SLOT_BOTTLE_2,
|
||||
/* 0x14 */ SLOT_BOTTLE_3,
|
||||
/* 0x15 */ SLOT_BOTTLE_4,
|
||||
/* 0x16 */ SLOT_TRADE_ADULT,
|
||||
/* 0x17 */ SLOT_TRADE_CHILD,
|
||||
/* 0x18 */ SLOT_IRON_BOOTS,
|
||||
/* 0x19 */ SLOT_HOVER_BOOTS,
|
||||
/* 0xFF */ SLOT_NONE = 0xFF
|
||||
} InventorySlot;
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ ITEM_STICK,
|
||||
/* 0x01 */ ITEM_NUT,
|
||||
/* 0x02 */ ITEM_BOMB,
|
||||
/* 0x03 */ ITEM_BOW,
|
||||
/* 0x04 */ ITEM_ARROW_FIRE,
|
||||
/* 0x05 */ ITEM_DINS_FIRE,
|
||||
/* 0x06 */ ITEM_SLINGSHOT,
|
||||
/* 0x07 */ ITEM_OCARINA_FAIRY,
|
||||
/* 0x08 */ ITEM_OCARINA_TIME,
|
||||
/* 0x09 */ ITEM_BOMBCHU,
|
||||
/* 0x0A */ ITEM_HOOKSHOT,
|
||||
/* 0x0B */ ITEM_LONGSHOT,
|
||||
/* 0x0C */ ITEM_ARROW_ICE,
|
||||
/* 0x0D */ ITEM_FARORES_WIND,
|
||||
/* 0x0E */ ITEM_BOOMERANG,
|
||||
/* 0x0F */ ITEM_LENS,
|
||||
/* 0x10 */ ITEM_BEAN,
|
||||
/* 0x11 */ ITEM_HAMMER,
|
||||
/* 0x12 */ ITEM_ARROW_LIGHT,
|
||||
/* 0x13 */ ITEM_NAYRUS_LOVE,
|
||||
/* 0x14 */ ITEM_BOTTLE,
|
||||
/* 0x15 */ ITEM_POTION_RED,
|
||||
/* 0x16 */ ITEM_POTION_GREEN,
|
||||
/* 0x17 */ ITEM_POTION_BLUE,
|
||||
/* 0x18 */ ITEM_FAIRY,
|
||||
/* 0x19 */ ITEM_FISH,
|
||||
/* 0x1A */ ITEM_MILK_BOTTLE,
|
||||
/* 0x1B */ ITEM_LETTER_RUTO,
|
||||
/* 0x1C */ ITEM_BLUE_FIRE,
|
||||
/* 0x1D */ ITEM_BUG,
|
||||
/* 0x1E */ ITEM_BIG_POE,
|
||||
/* 0x1F */ ITEM_MILK_HALF,
|
||||
/* 0x20 */ ITEM_POE,
|
||||
/* 0x21 */ ITEM_WEIRD_EGG,
|
||||
/* 0x22 */ ITEM_CHICKEN,
|
||||
/* 0x23 */ ITEM_LETTER_ZELDA,
|
||||
/* 0x24 */ ITEM_MASK_KEATON,
|
||||
/* 0x25 */ ITEM_MASK_SKULL,
|
||||
/* 0x26 */ ITEM_MASK_SPOOKY,
|
||||
/* 0x27 */ ITEM_MASK_BUNNY,
|
||||
/* 0x28 */ ITEM_MASK_GORON,
|
||||
/* 0x29 */ ITEM_MASK_ZORA,
|
||||
/* 0x2A */ ITEM_MASK_GERUDO,
|
||||
/* 0x2B */ ITEM_MASK_TRUTH,
|
||||
/* 0x2C */ ITEM_SOLD_OUT,
|
||||
/* 0x2D */ ITEM_POCKET_EGG,
|
||||
/* 0x2E */ ITEM_POCKET_CUCCO,
|
||||
/* 0x2F */ ITEM_COJIRO,
|
||||
/* 0x30 */ ITEM_ODD_MUSHROOM,
|
||||
/* 0x31 */ ITEM_ODD_POTION,
|
||||
/* 0x32 */ ITEM_SAW,
|
||||
/* 0x33 */ ITEM_SWORD_BROKEN,
|
||||
/* 0x34 */ ITEM_PRESCRIPTION,
|
||||
/* 0x35 */ ITEM_FROG,
|
||||
/* 0x36 */ ITEM_EYEDROPS,
|
||||
/* 0x37 */ ITEM_CLAIM_CHECK,
|
||||
/* 0x38 */ ITEM_BOW_ARROW_FIRE,
|
||||
/* 0x39 */ ITEM_BOW_ARROW_ICE,
|
||||
/* 0x3A */ ITEM_BOW_ARROW_LIGHT,
|
||||
/* 0x3B */ ITEM_SWORD_KOKIRI,
|
||||
/* 0x3C */ ITEM_SWORD_MASTER,
|
||||
/* 0x3D */ ITEM_SWORD_BGS,
|
||||
/* 0x3E */ ITEM_SHIELD_DEKU,
|
||||
/* 0x3F */ ITEM_SHIELD_HYLIAN,
|
||||
/* 0x40 */ ITEM_SHIELD_MIRROR,
|
||||
/* 0x41 */ ITEM_TUNIC_KOKIRI,
|
||||
/* 0x42 */ ITEM_TUNIC_GORON,
|
||||
/* 0x43 */ ITEM_TUNIC_ZORA,
|
||||
/* 0x44 */ ITEM_BOOTS_KOKIRI,
|
||||
/* 0x45 */ ITEM_BOOTS_IRON,
|
||||
/* 0x46 */ ITEM_BOOTS_HOVER,
|
||||
/* 0x47 */ ITEM_BULLET_BAG_30,
|
||||
/* 0x48 */ ITEM_BULLET_BAG_40,
|
||||
/* 0x49 */ ITEM_BULLET_BAG_50,
|
||||
/* 0x4A */ ITEM_QUIVER_30,
|
||||
/* 0x4B */ ITEM_QUIVER_40,
|
||||
/* 0x4C */ ITEM_QUIVER_50,
|
||||
/* 0x4D */ ITEM_BOMB_BAG_20,
|
||||
/* 0x4E */ ITEM_BOMB_BAG_30,
|
||||
/* 0x4F */ ITEM_BOMB_BAG_40,
|
||||
/* 0x50 */ ITEM_BRACELET,
|
||||
/* 0x51 */ ITEM_GAUNTLETS_SILVER,
|
||||
/* 0x52 */ ITEM_GAUNTLETS_GOLD,
|
||||
/* 0x53 */ ITEM_SCALE_SILVER,
|
||||
/* 0x54 */ ITEM_SCALE_GOLDEN,
|
||||
/* 0x55 */ ITEM_SWORD_KNIFE,
|
||||
/* 0x56 */ ITEM_WALLET_ADULT,
|
||||
/* 0x57 */ ITEM_WALLET_GIANT,
|
||||
/* 0x58 */ ITEM_SEEDS,
|
||||
/* 0x59 */ ITEM_FISHING_POLE,
|
||||
/* 0x5A */ ITEM_SONG_MINUET,
|
||||
/* 0x5B */ ITEM_SONG_BOLERO,
|
||||
/* 0x5C */ ITEM_SONG_SERENADE,
|
||||
/* 0x5D */ ITEM_SONG_REQUIEM,
|
||||
/* 0x5E */ ITEM_SONG_NOCTURNE,
|
||||
/* 0x5F */ ITEM_SONG_PRELUDE,
|
||||
/* 0x60 */ ITEM_SONG_LULLABY,
|
||||
/* 0x61 */ ITEM_SONG_EPONA,
|
||||
/* 0x62 */ ITEM_SONG_SARIA,
|
||||
/* 0x63 */ ITEM_SONG_SUN,
|
||||
/* 0x64 */ ITEM_SONG_TIME,
|
||||
/* 0x65 */ ITEM_SONG_STORMS,
|
||||
/* 0x66 */ ITEM_MEDALLION_FOREST,
|
||||
/* 0x67 */ ITEM_MEDALLION_FIRE,
|
||||
/* 0x68 */ ITEM_MEDALLION_WATER,
|
||||
/* 0x69 */ ITEM_MEDALLION_SPIRIT,
|
||||
/* 0x6A */ ITEM_MEDALLION_SHADOW,
|
||||
/* 0x6B */ ITEM_MEDALLION_LIGHT,
|
||||
/* 0x6C */ ITEM_KOKIRI_EMERALD,
|
||||
/* 0x6D */ ITEM_GORON_RUBY,
|
||||
/* 0x6E */ ITEM_ZORA_SAPPHIRE,
|
||||
/* 0x6F */ ITEM_STONE_OF_AGONY,
|
||||
/* 0x70 */ ITEM_GERUDO_CARD,
|
||||
/* 0x71 */ ITEM_SKULL_TOKEN,
|
||||
/* 0x72 */ ITEM_HEART_CONTAINER,
|
||||
/* 0x73 */ ITEM_HEART_PIECE,
|
||||
/* 0x74 */ ITEM_KEY_BOSS,
|
||||
/* 0x75 */ ITEM_COMPASS,
|
||||
/* 0x76 */ ITEM_DUNGEON_MAP,
|
||||
/* 0x77 */ ITEM_KEY_SMALL,
|
||||
/* 0x78 */ ITEM_MAGIC_SMALL,
|
||||
/* 0x79 */ ITEM_MAGIC_LARGE,
|
||||
/* 0x7A */ ITEM_HEART_PIECE_2,
|
||||
/* 0x7B */ ITEM_INVALID_1,
|
||||
/* 0x7C */ ITEM_INVALID_2,
|
||||
/* 0x7D */ ITEM_INVALID_3,
|
||||
/* 0x7E */ ITEM_INVALID_4,
|
||||
/* 0x7F */ ITEM_INVALID_5,
|
||||
/* 0x80 */ ITEM_INVALID_6,
|
||||
/* 0x81 */ ITEM_INVALID_7,
|
||||
/* 0x82 */ ITEM_MILK,
|
||||
/* 0x83 */ ITEM_HEART,
|
||||
/* 0x84 */ ITEM_RUPEE_GREEN,
|
||||
/* 0x85 */ ITEM_RUPEE_BLUE,
|
||||
/* 0x86 */ ITEM_RUPEE_RED,
|
||||
/* 0x87 */ ITEM_RUPEE_PURPLE,
|
||||
/* 0x88 */ ITEM_RUPEE_GOLD,
|
||||
/* 0x89 */ ITEM_INVALID_8,
|
||||
/* 0x8A */ ITEM_STICKS_5,
|
||||
/* 0x8B */ ITEM_STICKS_10,
|
||||
/* 0x8C */ ITEM_NUTS_5,
|
||||
/* 0x8D */ ITEM_NUTS_10,
|
||||
/* 0x8E */ ITEM_BOMBS_5,
|
||||
/* 0x8F */ ITEM_BOMBS_10,
|
||||
/* 0x90 */ ITEM_BOMBS_20,
|
||||
/* 0x91 */ ITEM_BOMBS_30,
|
||||
/* 0x92 */ ITEM_ARROWS_SMALL,
|
||||
/* 0x93 */ ITEM_ARROWS_MEDIUM,
|
||||
/* 0x94 */ ITEM_ARROWS_LARGE,
|
||||
/* 0x95 */ ITEM_SEEDS_30,
|
||||
/* 0x96 */ ITEM_BOMBCHUS_5,
|
||||
/* 0x97 */ ITEM_BOMBCHUS_20,
|
||||
/* 0x98 */ ITEM_STICK_UPGRADE_20,
|
||||
/* 0x99 */ ITEM_STICK_UPGRADE_30,
|
||||
/* 0x9A */ ITEM_NUT_UPGRADE_30,
|
||||
/* 0x9B */ ITEM_NUT_UPGRADE_40,
|
||||
/* 0xFF */ ITEM_NONE = 0xFF
|
||||
} ItemID;
|
||||
|
||||
// Get Item result may vary depending on context (chest/shop/scrub/drop)
|
||||
typedef enum {
|
||||
/* 0x00 */ GI_INVALID, // Link picks up chest and it sends him flying upwards
|
||||
/* 0x01 */ GI_BOMBS_5,
|
||||
/* 0x02 */ GI_NUTS_5,
|
||||
/* 0x03 */ GI_BOMBCHUS_10,
|
||||
/* 0x04 */ GI_BOW,
|
||||
/* 0x05 */ GI_SLINGSHOT,
|
||||
/* 0x06 */ GI_BOOMERANG,
|
||||
/* 0x07 */ GI_STICKS_1,
|
||||
/* 0x08 */ GI_HOOKSHOT,
|
||||
/* 0x09 */ GI_LONGSHOT,
|
||||
/* 0x0A */ GI_LENS,
|
||||
/* 0x0B */ GI_LETTER_ZELDA,
|
||||
/* 0x0C */ GI_OCARINA_OOT,
|
||||
/* 0x0D */ GI_HAMMER,
|
||||
/* 0x0E */ GI_COJIRO,
|
||||
/* 0x0F */ GI_BOTTLE,
|
||||
/* 0x10 */ GI_POTION_RED,
|
||||
/* 0x11 */ GI_POTION_GREEN,
|
||||
/* 0x12 */ GI_POTION_BLUE,
|
||||
/* 0x13 */ GI_FAIRY,
|
||||
/* 0x14 */ GI_MILK_BOTTLE,
|
||||
/* 0x15 */ GI_LETTER_RUTO,
|
||||
/* 0x16 */ GI_BEAN,
|
||||
/* 0x17 */ GI_MASK_SKULL,
|
||||
/* 0x18 */ GI_MASK_SPOOKY,
|
||||
/* 0x19 */ GI_CHICKEN, // uses bean message ID
|
||||
/* 0x1A */ GI_MASK_KEATON,
|
||||
/* 0x1B */ GI_MASK_BUNNY,
|
||||
/* 0x1C */ GI_MASK_TRUTH,
|
||||
/* 0x1D */ GI_POCKET_EGG,
|
||||
/* 0x1E */ GI_POCKET_CUCCO, // uses bean message ID
|
||||
/* 0x1F */ GI_ODD_MUSHROOM,
|
||||
/* 0x20 */ GI_ODD_POTION,
|
||||
/* 0x21 */ GI_SAW,
|
||||
/* 0x22 */ GI_SWORD_BROKEN,
|
||||
/* 0x23 */ GI_PERSCRIPTION,
|
||||
/* 0x24 */ GI_FROG,
|
||||
/* 0x25 */ GI_EYEDROPS,
|
||||
/* 0x26 */ GI_CLAIM_CHECK,
|
||||
/* 0x27 */ GI_SWORD_KOKIRI,
|
||||
/* 0x28 */ GI_SWORD_KNIFE,
|
||||
/* 0x29 */ GI_SHIELD_DEKU, // or blue rupee if you have the shield
|
||||
/* 0x2A */ GI_SHIELD_HYLIAN, // or blue rupee if you have the shield
|
||||
/* 0x2B */ GI_SHIELD_MIRROR,
|
||||
/* 0x2C */ GI_TUNIC_GORON, // or blue rupee if you have the tunic
|
||||
/* 0x2D */ GI_TUNIC_ZORA, // or blue rupee if you have the tunic
|
||||
/* 0x2E */ GI_BOOTS_IRON,
|
||||
/* 0x2F */ GI_BOOTS_HOVER,
|
||||
/* 0x30 */ GI_QUIVER_40,
|
||||
/* 0x31 */ GI_QUIVER_50,
|
||||
/* 0x32 */ GI_BOMB_BAG_20,
|
||||
/* 0x33 */ GI_BOMB_BAG_30,
|
||||
/* 0x34 */ GI_BOMB_BAG_40,
|
||||
/* 0x35 */ GI_GAUNTLETS_SILVER,
|
||||
/* 0x36 */ GI_GAUNTLETS_GOLD,
|
||||
/* 0x37 */ GI_SCALE_SILVER,
|
||||
/* 0x38 */ GI_SCALE_GOLD,
|
||||
/* 0x39 */ GI_STONE_OF_AGONY,
|
||||
/* 0x3A */ GI_GERUDO_CARD,
|
||||
/* 0x3B */ GI_OCARINA_FAIRY, // uses Ocarina of Time message ID
|
||||
/* 0x3C */ GI_SEEDS_5,
|
||||
/* 0x3D */ GI_HEART_CONTAINER,
|
||||
/* 0x3E */ GI_HEART_PIECE,
|
||||
/* 0x3F */ GI_KEY_BOSS,
|
||||
/* 0x40 */ GI_COMPASS,
|
||||
/* 0x41 */ GI_MAP,
|
||||
/* 0x42 */ GI_KEY_SMALL,
|
||||
/* 0x43 */ GI_MAGIC_SMALL, // or blue rupee if not from a drop
|
||||
/* 0x44 */ GI_MAGIC_LARGE, // or blue rupee if not from a drop
|
||||
/* 0x45 */ GI_WALLET_ADULT,
|
||||
/* 0x46 */ GI_WALLET_GIANT,
|
||||
/* 0x47 */ GI_WEIRD_EGG,
|
||||
/* 0x48 */ GI_HEART,
|
||||
/* 0x49 */ GI_ARROWS_SMALL, // amount changes depending on context
|
||||
/* 0x4A */ GI_ARROWS_MEDIUM, // amount changes depending on context
|
||||
/* 0x4B */ GI_ARROWS_LARGE, // amount changes depending on context
|
||||
/* 0x4C */ GI_RUPEE_GREEN,
|
||||
/* 0x4D */ GI_RUPEE_BLUE,
|
||||
/* 0x4E */ GI_RUPEE_RED,
|
||||
/* 0x4F */ GI_HEART_CONTAINER_2,
|
||||
/* 0x50 */ GI_MILK,
|
||||
/* 0x51 */ GI_MASK_GORON,
|
||||
/* 0x52 */ GI_MASK_ZORA,
|
||||
/* 0x53 */ GI_MASK_GERUDO,
|
||||
/* 0x54 */ GI_BRACELET,
|
||||
/* 0x55 */ GI_RUPEE_PURPLE,
|
||||
/* 0x56 */ GI_RUPEE_GOLD,
|
||||
/* 0x57 */ GI_SWORD_BGS,
|
||||
/* 0x58 */ GI_ARROW_FIRE,
|
||||
/* 0x59 */ GI_ARROW_ICE,
|
||||
/* 0x5A */ GI_ARROW_LIGHT,
|
||||
/* 0x5B */ GI_SKULL_TOKEN,
|
||||
/* 0x5C */ GI_DINS_FIRE,
|
||||
/* 0x5D */ GI_FARORES_WIND,
|
||||
/* 0x5E */ GI_NAYRUS_LOVE,
|
||||
/* 0x5F */ GI_BULLET_BAG_30,
|
||||
/* 0x60 */ GI_BULLET_BAG_40,
|
||||
/* 0x61 */ GI_STICKS_5,
|
||||
/* 0x62 */ GI_STICKS_10,
|
||||
/* 0x63 */ GI_NUTS_5_2,
|
||||
/* 0x64 */ GI_NUTS_10,
|
||||
/* 0x65 */ GI_BOMBS_1,
|
||||
/* 0x66 */ GI_BOMBS_10,
|
||||
/* 0x67 */ GI_BOMBS_20,
|
||||
/* 0x68 */ GI_BOMBS_30,
|
||||
/* 0x69 */ GI_SEEDS_30,
|
||||
/* 0x6A */ GI_BOMBCHUS_5,
|
||||
/* 0x6B */ GI_BOMBCHUS_20,
|
||||
/* 0x6C */ GI_FISH,
|
||||
/* 0x6D */ GI_BUGS,
|
||||
/* 0x6E */ GI_BLUE_FIRE,
|
||||
/* 0x6F */ GI_POE,
|
||||
/* 0x70 */ GI_BIG_POE,
|
||||
/* 0x71 */ GI_DOOR_KEY, // specific to chest minigame
|
||||
/* 0x72 */ GI_RUPEE_GREEN_LOSE, // specific to chest minigame
|
||||
/* 0x73 */ GI_RUPEE_BLUE_LOSE, // specific to chest minigame
|
||||
/* 0x74 */ GI_RUPEE_RED_LOSE, // specific to chest minigame
|
||||
/* 0x75 */ GI_RUPEE_PURPLE_LOSE, // specific to chest minigame
|
||||
/* 0x76 */ GI_HEART_PIECE_WIN, // specific to chest minigame
|
||||
/* 0x77 */ GI_STICK_UPGRADE_20,
|
||||
/* 0x78 */ GI_STICK_UPGRADE_30,
|
||||
/* 0x79 */ GI_NUT_UPGRADE_30,
|
||||
/* 0x7A */ GI_NUT_UPGRADE_40,
|
||||
/* 0x7B */ GI_BULLET_BAG_50,
|
||||
/* 0x7C */ GI_ICE_TRAP, // freezes link when opened from a chest
|
||||
/* 0x7D */ GI_TEXT_0, // no model appears over Link, shows text id 0 (pocket egg)
|
||||
/* 0x7E */ GI_SWORD_MASTER
|
||||
} GetItemID;
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ EXCH_ITEM_NONE,
|
||||
/* 0x01 */ EXCH_ITEM_LETTER_ZELDA,
|
||||
/* 0x02 */ EXCH_ITEM_WEIRD_EGG,
|
||||
/* 0x03 */ EXCH_ITEM_CHICKEN,
|
||||
/* 0x04 */ EXCH_ITEM_BEAN,
|
||||
/* 0x05 */ EXCH_ITEM_POCKET_EGG,
|
||||
/* 0x06 */ EXCH_ITEM_POCKET_CUCCO,
|
||||
/* 0x07 */ EXCH_ITEM_COJIRO,
|
||||
/* 0x08 */ EXCH_ITEM_ODD_MUSHROOM,
|
||||
/* 0x09 */ EXCH_ITEM_ODD_POTION,
|
||||
/* 0x0A */ EXCH_ITEM_SAW,
|
||||
/* 0x0B */ EXCH_ITEM_SWORD_BROKEN,
|
||||
/* 0x0C */ EXCH_ITEM_PRESCRIPTION,
|
||||
/* 0x0D */ EXCH_ITEM_FROG,
|
||||
/* 0x0E */ EXCH_ITEM_EYEDROPS,
|
||||
/* 0x0F */ EXCH_ITEM_CLAIM_CHECK,
|
||||
/* 0x10 */ EXCH_ITEM_MASK_SKULL,
|
||||
/* 0x11 */ EXCH_ITEM_MASK_SPOOKY,
|
||||
/* 0x12 */ EXCH_ITEM_MASK_KEATON,
|
||||
/* 0x13 */ EXCH_ITEM_MASK_BUNNY,
|
||||
/* 0x14 */ EXCH_ITEM_MASK_TRUTH,
|
||||
/* 0x15 */ EXCH_ITEM_MASK_GORON,
|
||||
/* 0x16 */ EXCH_ITEM_MASK_ZORA,
|
||||
/* 0x17 */ EXCH_ITEM_MASK_GERUDO,
|
||||
/* 0x18 */ EXCH_ITEM_FISH,
|
||||
/* 0x19 */ EXCH_ITEM_BLUE_FIRE,
|
||||
/* 0x1A */ EXCH_ITEM_BUG,
|
||||
/* 0x1B */ EXCH_ITEM_POE,
|
||||
/* 0x1C */ EXCH_ITEM_BIG_POE,
|
||||
/* 0x1D */ EXCH_ITEM_LETTER_RUTO,
|
||||
/* 0x1E */ EXCH_ITEM_MAX
|
||||
} ExchangeItemID;
|
||||
|
||||
#endif //_Z3D_ITEM_H_
|
38
include/z3D/z3Dvec.h
Normal file
38
include/z3D/z3Dvec.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef _Z3DVEC_H_
|
||||
#define _Z3DVEC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef float f32;
|
||||
typedef int8_t s8;
|
||||
typedef uint8_t u8;
|
||||
typedef int16_t s16;
|
||||
typedef uint16_t u16;
|
||||
typedef int32_t s32;
|
||||
typedef uint32_t u32;
|
||||
|
||||
typedef struct {
|
||||
f32 x, y;
|
||||
} Vec2f;
|
||||
|
||||
typedef struct {
|
||||
f32 x, y, z;
|
||||
} Vec3f;
|
||||
|
||||
typedef struct {
|
||||
s16 x, y, z;
|
||||
} Vec3s;
|
||||
|
||||
typedef struct {
|
||||
s32 x, y, z;
|
||||
} Vec3i;
|
||||
|
||||
typedef struct {
|
||||
f32 data[3][4];
|
||||
} nn_math_MTX34;
|
||||
|
||||
typedef struct {
|
||||
f32 data[4][4];
|
||||
} nn_math_MTX44;
|
||||
|
||||
#endif
|
29
makeAll.sh
Normal file
29
makeAll.sh
Normal file
@@ -0,0 +1,29 @@
|
||||
make clean
|
||||
make -j REGION=EUR
|
||||
echo Moving to ./Patch Files/EUR/3DS/code.ips
|
||||
mv code.ips "./Patch Files/EUR/3DS/code.ips"
|
||||
|
||||
make clean
|
||||
make -j REGION=EUR citra=1
|
||||
echo Moving to ./Patch Files/EUR/Citra/code.ips
|
||||
mv code.ips "./Patch Files/EUR/Citra/code.ips"
|
||||
|
||||
make clean
|
||||
make -j REGION=JP
|
||||
echo Moving to ./Patch Files/JP/3DS/code.ips
|
||||
mv code.ips "./Patch Files/JP/3DS/code.ips"
|
||||
|
||||
make clean
|
||||
make -j REGION=JP citra=1
|
||||
echo Moving to ./Patch Files/JP/Citra/code.ips
|
||||
mv code.ips "./Patch Files/JP/Citra/code.ips"
|
||||
|
||||
make clean
|
||||
make -j REGION=USA citra=1
|
||||
echo Moving to ./Patch Files/USA/Citra/code.ips
|
||||
mv code.ips "./Patch Files/USA/Citra/code.ips"
|
||||
|
||||
make clean
|
||||
make -j REGION=USA
|
||||
echo Moving to ./Patch Files/USA/3DS/code.ips
|
||||
mv code.ips "./Patch Files/USA/3DS/code.ips"
|
36
oot.ld
Normal file
36
oot.ld
Normal file
@@ -0,0 +1,36 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(loader_patch)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
.patch_loader 0x100000 : {
|
||||
*(.patch_loader)
|
||||
}
|
||||
|
||||
.patch_CameraUpdate 0x2D84C8 : {
|
||||
* (.patch_CameraUpdate)
|
||||
}
|
||||
|
||||
.patch_before_GlobalContext_Update 0x452390 : {
|
||||
*(.patch_before_GlobalContext_Update)
|
||||
}
|
||||
|
||||
. = 0x4C99A8;
|
||||
. = ALIGN(4);
|
||||
.loader : {
|
||||
*(.loader*)
|
||||
}
|
||||
|
||||
. = 0x005C7000;
|
||||
.text : {
|
||||
__text_start = . ;
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.data)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
__text_end = . ;
|
||||
}
|
||||
}
|
36
oot_e.ld
Normal file
36
oot_e.ld
Normal file
@@ -0,0 +1,36 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(loader_patch)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
.patch_loader 0x100000 : {
|
||||
*(.patch_loader)
|
||||
}
|
||||
|
||||
.patch_CameraUpdate 0x2D84C8 : {
|
||||
* (.patch_CameraUpdate)
|
||||
}
|
||||
|
||||
.patch_before_GlobalContext_Update 0x4523B0 : {
|
||||
*(.patch_before_GlobalContext_Update)
|
||||
}
|
||||
|
||||
. = 0x4C99A8;
|
||||
. = ALIGN(4);
|
||||
.loader : {
|
||||
*(.loader*)
|
||||
}
|
||||
|
||||
. = 0x005C7000;
|
||||
.text : {
|
||||
__text_start = . ;
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.data)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
__text_end = . ;
|
||||
}
|
||||
}
|
36
oot_j.ld
Normal file
36
oot_j.ld
Normal file
@@ -0,0 +1,36 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(loader_patch)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
.patch_loader 0x100000 : {
|
||||
*(.patch_loader)
|
||||
}
|
||||
|
||||
.patch_CameraUpdate 0x2D7FE0 : {
|
||||
* (.patch_CameraUpdate)
|
||||
}
|
||||
|
||||
.patch_before_GlobalContext_Update 0x452368 : {
|
||||
*(.patch_before_GlobalContext_Update)
|
||||
}
|
||||
|
||||
. = 0x4C99A8;
|
||||
. = ALIGN(4);
|
||||
.loader : {
|
||||
*(.loader*)
|
||||
}
|
||||
|
||||
. = 0x005C7000;
|
||||
.text : {
|
||||
__text_start = . ;
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.data)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
__text_end = . ;
|
||||
}
|
||||
}
|
44
patch.py
Normal file
44
patch.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import os
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
elf = sys.argv[1]
|
||||
result = subprocess.run([os.environ["DEVKITARM"] + r'/bin/arm-none-eabi-objdump', '--section-headers', elf], stdout=subprocess.PIPE)
|
||||
lines = str(result.stdout).split('\\n')
|
||||
sectionsInfo = [line.split()[1:6] for line in lines if line.split() and line.split()[0].isdigit()]
|
||||
sections = ((int(sec[2],16), int(sec[4],16), int(sec[1],16)) for sec in sectionsInfo if int(sec[2],16) != 0)
|
||||
|
||||
|
||||
off = lambda vaddr: struct.pack(">I",vaddr - 0x100000)[1:]
|
||||
sz = lambda size: struct.pack(">H", size)
|
||||
|
||||
ips = b'PATCH'
|
||||
with open(elf, 'rb') as e:
|
||||
for vaddr, offset, size in sections:
|
||||
|
||||
if vaddr >= 0x4CA000 and vaddr < 0x5C7000: #this is not good lol just trying to avoid __GNU_EH_FRAME_HDR section
|
||||
continue
|
||||
|
||||
e.seek(offset, 0)
|
||||
while size > 65535:
|
||||
patch = e.read(65535)
|
||||
# print('{:0x}'.format(vaddr))
|
||||
ips += off(vaddr)
|
||||
ips += sz(65535)
|
||||
ips += patch
|
||||
vaddr += 65535
|
||||
offset += 65535
|
||||
size -= 65535
|
||||
|
||||
patch = e.read(size)
|
||||
if len(patch) != 0:
|
||||
# print('{:0x}'.format(vaddr))
|
||||
ips += off(vaddr)
|
||||
ips += sz(size)
|
||||
ips += patch
|
||||
ips += b'EOF'
|
||||
|
||||
with open("code.ips", 'wb') as patchFile:
|
||||
patchFile.write(ips)
|
||||
print("created basecode.ips\n")
|
252
src/camera.c
Normal file
252
src/camera.c
Normal file
@@ -0,0 +1,252 @@
|
||||
#include "z3D/z3D.h"
|
||||
#include "common.h"
|
||||
#include "input.h"
|
||||
|
||||
#define GyroDrawHUDIcon *(u8*)0x4FC648
|
||||
s16 pitch = 0, yaw = 0;
|
||||
f32 dist = 0;
|
||||
|
||||
f32 sins(u16 angle) {
|
||||
// Taylor expansion up to x^7. Use symmetries for larger angles.
|
||||
if (angle <= 0x4000) {
|
||||
f32 theta = angle * 0.0000958737992429, theta2 = theta * theta, result = theta;
|
||||
theta *= theta2 * 0.166666666667;
|
||||
result -= theta;
|
||||
theta *= theta2 * 0.05;
|
||||
result += theta;
|
||||
theta *= theta2 * 0.0238095238095;
|
||||
result -= theta;
|
||||
return result;
|
||||
} else if (angle <= 0x8000) {
|
||||
return sins(0x8000 - angle);
|
||||
}
|
||||
return -sins(angle - 0x8000);
|
||||
}
|
||||
|
||||
f32 coss(u16 angle) {
|
||||
return sins(angle + 0x4000);
|
||||
}
|
||||
|
||||
f32 sqrtf(f32 x) {
|
||||
f32 n = (1 + x) * 0.5;
|
||||
|
||||
while (n * n < x * 0.999f || n * n > x * 1.001f) {
|
||||
n = (n + x / n) * 0.5;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
f32 distXYZ(Vec3f a, Vec3f b) {
|
||||
f32 x = a.x - b.x, y = a.y - b.y, z = a.z - b.z;
|
||||
return sqrtf(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
f32 distXZ(Vec3f a, Vec3f b) {
|
||||
f32 x = a.x - b.x, z = a.z - b.z;
|
||||
return sqrtf(x * x + z * z);
|
||||
}
|
||||
|
||||
s16 Clamp(f32 val) {
|
||||
if (val >= 0x3000)
|
||||
return 0x3000;
|
||||
if (val <= -0x3000)
|
||||
return -0x3000;
|
||||
return (s16)val;
|
||||
}
|
||||
|
||||
f32 lerpf(f32 a, f32 b, f32 t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
Vec3f lerpv(Vec3f a, Vec3f b, f32 t) {
|
||||
a.x += (b.x - a.x) * t;
|
||||
a.y += (b.y - a.y) * t;
|
||||
a.z += (b.z - a.z) * t;
|
||||
return a;
|
||||
}
|
||||
|
||||
// Original function got inlined so recreated with help from decomp
|
||||
#define CAM_DEG_TO_BINANG(degrees) (s16)(s32)((degrees)*182.04167 + 0.5)
|
||||
void Camera_UpdateDistortion(Camera* camera) {
|
||||
static u16 screenPlanePhase = 0;
|
||||
f32 screenPlanePhaseStep;
|
||||
f32 xScale;
|
||||
f32 yScale;
|
||||
f32 speed;
|
||||
f32 speedFactor;
|
||||
f32 scaleFactor;
|
||||
|
||||
if (camera->distortionFlags) {
|
||||
if (camera->distortionFlags & 4) {
|
||||
// DISTORTION_UNDERWATER_MEDIUM
|
||||
screenPlanePhaseStep = 170;
|
||||
xScale = -0.01;
|
||||
yScale = 0.01;
|
||||
speed = 0.6;
|
||||
scaleFactor = camera->waterDistortionTimer / 60.0;
|
||||
speedFactor = 1;
|
||||
} else if (camera->distortionFlags & 8) {
|
||||
// DISTORTION_UNDERWATER_STRONG
|
||||
screenPlanePhaseStep = -90;
|
||||
xScale = -0.22;
|
||||
yScale = 0.12;
|
||||
speed = 0.1;
|
||||
scaleFactor = camera->waterDistortionTimer / 80.0;
|
||||
speedFactor = 1;
|
||||
} else if (camera->distortionFlags & 2) {
|
||||
// DISTORTION_UNDERWATER_WEAK
|
||||
screenPlanePhaseStep = -18.5;
|
||||
xScale = 0.09;
|
||||
yScale = 0.09;
|
||||
speed = 0.08;
|
||||
scaleFactor = camera->waterYPos - camera->eye.y;
|
||||
scaleFactor = ((scaleFactor > 150) ? 1 : scaleFactor / 150) * 0.45 + camera->speedRatio * 0.45;
|
||||
speedFactor = scaleFactor;
|
||||
} else if (camera->distortionFlags & 1) {
|
||||
// DISTORTION_HOT_ROOM
|
||||
screenPlanePhaseStep = 150;
|
||||
xScale = -0.01;
|
||||
yScale = 0.01;
|
||||
speed = 0.6;
|
||||
scaleFactor = 1;
|
||||
speedFactor = 1;
|
||||
} else {
|
||||
// DISTORTION_UNDERWATER_FISHING
|
||||
return;
|
||||
}
|
||||
|
||||
screenPlanePhase += CAM_DEG_TO_BINANG(screenPlanePhaseStep * 2 / 3.0);
|
||||
speedFactor *= 2 / 3.0;
|
||||
|
||||
camera->globalCtx->view.distortionScale.x = xScale * scaleFactor * sins(screenPlanePhase) + 1;
|
||||
camera->globalCtx->view.distortionScale.y = yScale * scaleFactor * coss(screenPlanePhase) + 1;
|
||||
camera->globalCtx->view.distortionSpeed = speed * speedFactor;
|
||||
|
||||
camera->stateFlags |= 0x0040;
|
||||
} else if (camera->stateFlags & 0x0040) {
|
||||
camera->globalCtx->view.distortionScale.x = 1;
|
||||
camera->globalCtx->view.distortionScale.y = 1;
|
||||
camera->globalCtx->view.distortionSpeed = 1;
|
||||
camera->stateFlags &= ~0x0040;
|
||||
}
|
||||
}
|
||||
|
||||
s32 Camera_UpdateHotRoom(Camera* camera) {
|
||||
camera->distortionFlags &= 0xFFFE;
|
||||
// Parts of RoomContext, bool value seems new to 3D
|
||||
if (camera->globalCtx->unk_4C31[1] == 3 || camera->globalCtx->unk_4C31[6]) {
|
||||
camera->distortionFlags |= 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
char hd2c(u32 hd) {
|
||||
if (hd < 10)
|
||||
return hd + 48;
|
||||
return hd + 55;
|
||||
}
|
||||
|
||||
u8 Camera_FreeCamEnabled(Camera* camera) {
|
||||
static u8 freeCamEnabled = 0;
|
||||
|
||||
// Keep track of these to smoothly switch to free cam
|
||||
dist = distXYZ(camera->at, camera->eye);
|
||||
if (!freeCamEnabled) {
|
||||
pitch = camera->camDir.x;
|
||||
yaw = camera->camDir.y;
|
||||
}
|
||||
|
||||
// Deadzone of 30 units
|
||||
if (rInputCtx.cStick.dx * rInputCtx.cStick.dx + rInputCtx.cStick.dy * rInputCtx.cStick.dy > 900) {
|
||||
freeCamEnabled = 1;
|
||||
}
|
||||
|
||||
// Titlescreen or cutscene or no player or targeting or first person or cutscene or horse or crawlspace or special
|
||||
// camera state/setting (MK balcony, chu bowling, static, rotating, hedge maze, GF cells, shops, back alley)
|
||||
if (!IsInGameOrBossChallenge() || camera != &camera->globalCtx->mainCamera || !camera->player ||
|
||||
camera->player->stateFlags1 & 0x20938230 || camera->player->stateFlags2 & 0x00040000 || camera->status != 7 ||
|
||||
camera->setting == 0x14 || camera->setting == 0x15 || camera->setting == 0x19 || camera->setting == 0x1A ||
|
||||
camera->setting == 0x1B || camera->setting == 0x23 || camera->setting == 0x40 || camera->setting == 0x46) {
|
||||
freeCamEnabled = 0;
|
||||
}
|
||||
|
||||
return freeCamEnabled;
|
||||
}
|
||||
|
||||
void Camera_FreeCamUpdate(Vec3s* out, Camera* camera) {
|
||||
Camera_CheckWater(camera); // Changes skybox colour and audio when camera is underwater
|
||||
Camera_UpdateHotRoom(camera); // Check if in a hot room (mainly for DC load planes)
|
||||
Camera_UpdateDistortion(camera); // Handle heat/water screen distortions
|
||||
Camera_UpdateInterface(0); // Remove the black bars at the top/bottom of the screen
|
||||
GyroDrawHUDIcon = 0; // Remove the icon in the top right indicating motion controls
|
||||
if (camera->player) {
|
||||
Vec3f at;
|
||||
CamColChk eye;
|
||||
|
||||
// Fixes some weird camera behaviour when leaving free cam out of bounds
|
||||
// Causes some issues with pulling objects so don't run while in bounds
|
||||
if (!camera->player->actor.floorPoly) {
|
||||
camera->animState = 1;
|
||||
camera->behaviorFlags = 0;
|
||||
}
|
||||
|
||||
// Aim camera at Link's head. Aim lower when hanging from a ledge as position and model become disjointed
|
||||
camera->playerPosRot = camera->player->actor.world;
|
||||
at = eye.pos = camera->playerPosRot.pos;
|
||||
at.y = eye.pos.y += ((gSaveContext.linkAge) ? 38 : 50) * ((camera->player->stateFlags1 & 0x00002000) ? 0.5 : 1);
|
||||
|
||||
// TODO: options for inverted axes and sensitivity
|
||||
if (rInputCtx.cStick.dx * rInputCtx.cStick.dx + rInputCtx.cStick.dy * rInputCtx.cStick.dy > 900) {
|
||||
// Invert X input in mirror world
|
||||
yaw -= rInputCtx.cStick.dx * 8 * ((gSaveContext.masterQuestFlag) ? -1 : 1);
|
||||
pitch = Clamp(pitch + rInputCtx.cStick.dy * 8);
|
||||
}
|
||||
|
||||
// Set intended camera position
|
||||
dist = lerpf(dist, ((gSaveContext.linkAge) ? 150 : 200) - 50 * sins(pitch), 0.5);
|
||||
eye.pos.x -= dist * coss(pitch) * sins(yaw);
|
||||
eye.pos.y -= dist * sins(pitch);
|
||||
eye.pos.z -= dist * coss(pitch) * coss(yaw);
|
||||
// Move intended position in front of collision
|
||||
Camera_BGCheckInfo(camera, &at, &eye);
|
||||
|
||||
// Move actual camera positions towards intended positions
|
||||
camera->globalCtx->view.at = camera->at = lerpv(camera->at, at, 0.3);
|
||||
camera->globalCtx->view.eye = camera->eye = camera->eyeNext = lerpv(camera->eye, eye.pos, 0.3);
|
||||
|
||||
// Apply quake offsets
|
||||
ShakeInfo camShake;
|
||||
if (Quake_Update(camera, &camShake)) {
|
||||
camera->globalCtx->view.at.x += camShake.atOffset.x;
|
||||
camera->globalCtx->view.at.y += camShake.atOffset.y;
|
||||
camera->globalCtx->view.at.z += camShake.atOffset.z;
|
||||
camera->globalCtx->view.eye.x += camShake.eyeOffset.x;
|
||||
camera->globalCtx->view.eye.y += camShake.eyeOffset.y;
|
||||
camera->globalCtx->view.eye.z += camShake.eyeOffset.z;
|
||||
}
|
||||
|
||||
// Set up vector
|
||||
camera->globalCtx->view.up.x = 0;
|
||||
camera->globalCtx->view.up.y = 1;
|
||||
camera->globalCtx->view.up.z = 0;
|
||||
|
||||
// Set the direction of control stick inputs
|
||||
out->x = camera->inputDir.x = camera->camDir.x = pitch;
|
||||
out->y = camera->inputDir.y = camera->camDir.y = yaw;
|
||||
out->z = camera->inputDir.z = camera->camDir.z = 0;
|
||||
|
||||
// Update camera setting
|
||||
// TODO: use correct method for finding floor poly
|
||||
s16 newCamDataIdx = Camera_GetCamDataId(&camera->globalCtx->colCtx, camera->player->actor.floorPoly, 0x32);
|
||||
s16 newSetting = camera->globalCtx->colCtx.stat.colHeader->camDataList[newCamDataIdx].setting;
|
||||
if (newCamDataIdx != -1 && newSetting && (newSetting != 0x35 || gSaveContext.linkAge)) {
|
||||
camera->camDataIdx = newCamDataIdx;
|
||||
if (newSetting != camera->setting) {
|
||||
camera->prevSetting = camera->setting;
|
||||
camera->setting = newSetting;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
31
src/hooks.s
Normal file
31
src/hooks.s
Normal file
@@ -0,0 +1,31 @@
|
||||
.arm
|
||||
.text
|
||||
|
||||
.global hook_before_GlobalContext_Update
|
||||
hook_before_GlobalContext_Update:
|
||||
push {r0-r12, lr}
|
||||
bl before_GlobalContext_Update
|
||||
pop {r0-r12, lr}
|
||||
cpy r7,r0
|
||||
bx lr
|
||||
|
||||
.section .loader
|
||||
.global hook_into_loader
|
||||
hook_into_loader:
|
||||
push {r0-r12, lr}
|
||||
bl loader_main
|
||||
pop {r0-r12, lr}
|
||||
bl 0x100028
|
||||
b 0x100004
|
||||
|
||||
.global hook_CameraUpdate
|
||||
hook_CameraUpdate:
|
||||
push {r0-r12, lr}
|
||||
cpy r0,r1
|
||||
bl Camera_FreeCamEnabled
|
||||
cmp r0,#0x0
|
||||
pop {r0-r12, lr}
|
||||
cpyeq r6,r0
|
||||
bxeq lr
|
||||
bl Camera_FreeCamUpdate
|
||||
ldmia sp!,{r4-r11,pc}
|
63
src/includes/common.c
Normal file
63
src/includes/common.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "common.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "lib/printf.h"
|
||||
|
||||
s8 BitCompare(u32 value1, u32 value2, u8 bit) {
|
||||
if ((value1 & (1 << bit)) > (value2 & (1 << bit))) {
|
||||
return 1;
|
||||
} else if ((value2 & (1 << bit)) > (value1 & (1 << bit))) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// From section 5 of https://www.cs.ubc.ca/~rbridson/docs/schechter-sca08-turbulence.pdf
|
||||
u32 Hash(u32 state) {
|
||||
state ^= 0xDC3A653D;
|
||||
state *= 0xE1C88647;
|
||||
state ^= state >> 16;
|
||||
state *= 0xE1C88647;
|
||||
state ^= state >> 16;
|
||||
state *= 0xE1C88647;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
u8 And(u32 seed, u8 start, u8 end) {
|
||||
u8 value = 1;
|
||||
|
||||
for (u8 i = start; i < end && value; i++) {
|
||||
value &= seed >> i;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
u8 Bias(u32 seed) {
|
||||
u8 value = (seed & 0x00000007);
|
||||
value |= And(seed, 3, 5) << 3;
|
||||
value |= And(seed, 5, 7) << 4;
|
||||
value |= And(seed, 7, 11) << 5;
|
||||
value |= And(seed, 11, 16) << 6;
|
||||
return value;
|
||||
}
|
||||
|
||||
u8 IsInGame(void) {
|
||||
return IsInGameOrBossChallenge() && !BossChallenge_IsActive();
|
||||
}
|
||||
|
||||
u8 IsInGameOrBossChallenge(void) {
|
||||
s32 entr = gSaveContext.entranceIndex;
|
||||
s32 mode = gSaveContext.gameMode;
|
||||
return mode == 0 || (mode == 1 && (gSaveContext.cutsceneIndex < 0xFFF0 ||
|
||||
(entr != 0x0629 && entr != 0x0147 && entr != 0x00A0 && entr != 0x008D)));
|
||||
}
|
||||
|
||||
void CitraPrint(const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
char buf[128];
|
||||
int length = vsnprintf(buf, 128, message, args);
|
||||
svcOutputDebugString(buf, length);
|
||||
va_end(args);
|
||||
}
|
101
src/includes/csvc.s
Normal file
101
src/includes/csvc.s
Normal file
@@ -0,0 +1,101 @@
|
||||
@ 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
|
||||
svc 0xA0
|
||||
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 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
|
66
src/includes/env.c
Normal file
66
src/includes/env.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/* Source: https://github.com/devkitPro/libctru/blob/6360f4bdb1ca5f8131ffc92640c1dd16afb63083/libctru/source/env.c */
|
||||
|
||||
#include "3ds/types.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "3ds/env.h"
|
||||
|
||||
/*
|
||||
The homebrew loader can choose to supply a list of service handles that have
|
||||
been "stolen" from other processes that have been compromised. This allows us
|
||||
to access services that are normally restricted from the current process.
|
||||
|
||||
For every service requested by the application, we shall first check if the
|
||||
list given to us contains the requested service and if so use it. If we don't
|
||||
find the service in that list, we ask the service manager and hope for the
|
||||
best.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u32 num;
|
||||
|
||||
struct {
|
||||
char name[8];
|
||||
Handle handle;
|
||||
} services[];
|
||||
} service_list_t;
|
||||
|
||||
static int __name_cmp(const char* a, const char* b) {
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (a[i] != b[i])
|
||||
return 1;
|
||||
if (a[i] == '\0')
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle __attribute__((weak)) envGetHandle(const char* name) {
|
||||
if (__service_ptr == NULL)
|
||||
return 0;
|
||||
|
||||
service_list_t* service_list = (service_list_t*)__service_ptr;
|
||||
u32 i, num = service_list->num;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (__name_cmp(service_list->services[i].name, name) == 0)
|
||||
return service_list->services[i].handle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __attribute__((weak)) envDestroyHandles(void) {
|
||||
if (__service_ptr == NULL)
|
||||
return;
|
||||
|
||||
service_list_t* service_list = (service_list_t*)__service_ptr;
|
||||
u32 i, num = service_list->num;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
svcCloseHandle(service_list->services[i].handle);
|
||||
|
||||
service_list->num = 0;
|
||||
}
|
85
src/includes/input.c
Normal file
85
src/includes/input.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "input.h"
|
||||
|
||||
#include "z3D/z3D.h"
|
||||
#include "hid.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "utils.h"
|
||||
#include "3ds/types.h"
|
||||
|
||||
#define HID_PAD (real_hid.pad.pads[real_hid.pad.index].curr.val)
|
||||
|
||||
InputContext rInputCtx;
|
||||
|
||||
void Input_Update(void) {
|
||||
rInputCtx.cur.val = real_hid.pad.pads[real_hid.pad.index].curr.val;
|
||||
rInputCtx.pressed.val = (rInputCtx.cur.val) & (~rInputCtx.old.val);
|
||||
rInputCtx.up.val = (~rInputCtx.cur.val) & (rInputCtx.old.val);
|
||||
rInputCtx.old.val = rInputCtx.cur.val;
|
||||
rInputCtx.touchX = real_hid.touch.touches[real_hid.touch.index].touch.x;
|
||||
rInputCtx.touchY = real_hid.touch.touches[real_hid.touch.index].touch.y;
|
||||
rInputCtx.touchPressed = real_hid.touch.touches[real_hid.touch.index].updated && !rInputCtx.touchHeld;
|
||||
rInputCtx.touchHeld = real_hid.touch.touches[real_hid.touch.index].updated;
|
||||
|
||||
irrstScanInput();
|
||||
irrstCstickRead(&(rInputCtx.cStick));
|
||||
}
|
||||
|
||||
u32 buttonCheck(u32 key) {
|
||||
for (u32 i = 0x26000; i > 0; i--) {
|
||||
if (key != real_hid.pad.pads[real_hid.pad.index].curr.val)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 Input_WaitWithTimeout(u32 msec, u32 closingButton) {
|
||||
u32 pressedKey = 0;
|
||||
u32 key = 0;
|
||||
u32 n = 0;
|
||||
u32 startingButtonState = HID_PAD;
|
||||
|
||||
// Wait for no keys to be pressed
|
||||
while (HID_PAD && (msec == 0 || n <= msec)) {
|
||||
svcSleepThread(1 * 1000 * 1000LL);
|
||||
n++;
|
||||
|
||||
// If the player presses the closing button while still holding other buttons, the menu closes (useful for
|
||||
// buffering);
|
||||
u32 tempButtons = HID_PAD;
|
||||
if (tempButtons != startingButtonState && buttonCheck(tempButtons)) {
|
||||
|
||||
if (tempButtons & closingButton) {
|
||||
break;
|
||||
} else {
|
||||
startingButtonState = tempButtons;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msec != 0 && n >= msec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
// Wait for a key to be pressed
|
||||
while (!HID_PAD && (msec == 0 || n < msec)) {
|
||||
svcSleepThread(1 * 1000 * 1000LL);
|
||||
n++;
|
||||
}
|
||||
|
||||
if (msec != 0 && n >= msec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
key = HID_PAD;
|
||||
|
||||
// Make sure it's pressed
|
||||
pressedKey = buttonCheck(key);
|
||||
} while (!pressedKey);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
u32 Input_Wait(void) {
|
||||
return Input_WaitWithTimeout(0, 0);
|
||||
}
|
181
src/includes/irrst.c
Normal file
181
src/includes/irrst.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
_irrst.c - C-stick, ZL/ZR
|
||||
Edited from
|
||||
https://github.com/devkitPro/libctru/blob/b18f04d88739283f6ffb55fe5ea77c73796cf61b/libctru/source/services/irrst.c
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "3ds/types.h"
|
||||
#include "3ds/result.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "3ds/srv.h"
|
||||
#include "3ds/allocator/mappable.h"
|
||||
#include "3ds/synchronization.h"
|
||||
#include "3ds/services/irrst.h"
|
||||
#include "3ds/ipc.h"
|
||||
#include "3ds/env.h"
|
||||
|
||||
Handle irrstHandle;
|
||||
Handle irrstMemHandle;
|
||||
Handle irrstEvent;
|
||||
|
||||
vu32* irrstSharedMem;
|
||||
|
||||
static u32 kHeld;
|
||||
static circlePosition csPos;
|
||||
static int irrstRefCount;
|
||||
|
||||
Result irrstInit(void) {
|
||||
if (AtomicPostIncrement(&irrstRefCount))
|
||||
return 0;
|
||||
mappableInit(OS_MAP_AREA_BEGIN, OS_MAP_AREA_END);
|
||||
|
||||
Result ret = 0;
|
||||
|
||||
// Request service.
|
||||
if (R_FAILED(ret = srvGetServiceHandle(&irrstHandle, "ir:rst")))
|
||||
goto cleanup0;
|
||||
|
||||
// Get sharedmem handle.
|
||||
if (R_FAILED(ret = IRRST_GetHandles(&irrstMemHandle, &irrstEvent)))
|
||||
goto cleanup1;
|
||||
|
||||
// Initialize ir:rst
|
||||
if (envGetHandle("ir:rst") == 0)
|
||||
ret = IRRST_Initialize(10, 0);
|
||||
|
||||
// Map ir:rst shared memory.
|
||||
irrstSharedMem = (vu32*)mappableAlloc(0x98);
|
||||
if (!irrstSharedMem) {
|
||||
ret = -1;
|
||||
goto cleanup1;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = svcMapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem, MEMPERM_READ, MEMPERM_DONTCARE)))
|
||||
goto cleanup2;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup2:
|
||||
svcCloseHandle(irrstMemHandle);
|
||||
if (irrstSharedMem != NULL) {
|
||||
mappableFree((void*)irrstSharedMem);
|
||||
irrstSharedMem = NULL;
|
||||
}
|
||||
cleanup1:
|
||||
svcCloseHandle(irrstHandle);
|
||||
cleanup0:
|
||||
AtomicDecrement(&irrstRefCount);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void irrstExit(void) {
|
||||
if (AtomicDecrement(&irrstRefCount))
|
||||
return;
|
||||
|
||||
// Reset internal state.
|
||||
kHeld = 0;
|
||||
|
||||
svcCloseHandle(irrstEvent);
|
||||
// Unmap ir:rst sharedmem and close handles.
|
||||
svcUnmapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem);
|
||||
if (envGetHandle("ir:rst") == 0)
|
||||
IRRST_Shutdown();
|
||||
svcCloseHandle(irrstMemHandle);
|
||||
svcCloseHandle(irrstHandle);
|
||||
|
||||
if (irrstSharedMem != NULL) {
|
||||
mappableFree((void*)irrstSharedMem);
|
||||
irrstSharedMem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void irrstWaitForEvent(bool nextEvent) {
|
||||
if (nextEvent)
|
||||
svcClearEvent(irrstEvent);
|
||||
svcWaitSynchronization(irrstEvent, U64_MAX);
|
||||
if (!nextEvent)
|
||||
svcClearEvent(irrstEvent);
|
||||
}
|
||||
|
||||
u32 irrstCheckSectionUpdateTime(vu32* sharedmem_section, u32 id) {
|
||||
s64 tick0 = 0, tick1 = 0;
|
||||
|
||||
if (id == 0) {
|
||||
tick0 = *((u64*)&sharedmem_section[0]);
|
||||
tick1 = *((u64*)&sharedmem_section[2]);
|
||||
|
||||
if (tick0 == tick1 || tick0 < 0 || tick1 < 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void irrstScanInput(void) {
|
||||
if (irrstRefCount == 0)
|
||||
return;
|
||||
|
||||
u32 Id = 0;
|
||||
kHeld = 0;
|
||||
memset(&csPos, 0, sizeof(circlePosition));
|
||||
|
||||
Id = irrstSharedMem[4]; // PAD / circle-pad
|
||||
if (Id > 7)
|
||||
Id = 7;
|
||||
if (irrstCheckSectionUpdateTime(irrstSharedMem, Id) == 0) {
|
||||
kHeld = irrstSharedMem[6 + Id * 4];
|
||||
csPos = *(circlePosition*)&irrstSharedMem[6 + Id * 4 + 3];
|
||||
}
|
||||
}
|
||||
|
||||
u32 irrstKeysHeld(void) {
|
||||
if (irrstRefCount > 0)
|
||||
return kHeld;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void irrstCstickRead(circlePosition* pos) {
|
||||
if (pos)
|
||||
*pos = csPos;
|
||||
}
|
||||
|
||||
Result IRRST_GetHandles(Handle* outMemHandle, Handle* outEventHandle) {
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(0x1, 0, 0); // 0x10000
|
||||
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = svcSendSyncRequest(irrstHandle)))
|
||||
return ret;
|
||||
|
||||
if (outMemHandle)
|
||||
*outMemHandle = cmdbuf[3];
|
||||
if (outEventHandle)
|
||||
*outEventHandle = cmdbuf[4];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result IRRST_Initialize(u32 unk1, u8 unk2) {
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(0x2, 2, 0); // 0x20080
|
||||
cmdbuf[1] = unk1;
|
||||
cmdbuf[2] = unk2;
|
||||
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = svcSendSyncRequest(irrstHandle)))
|
||||
return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result IRRST_Shutdown(void) {
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(0x3, 0, 0); // 0x30000
|
||||
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = svcSendSyncRequest(irrstHandle)))
|
||||
return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
43
src/includes/loader.c
Normal file
43
src/includes/loader.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is a modified version of a file originally written by RicBent
|
||||
* for the program Magikoopa.
|
||||
*/
|
||||
|
||||
#include "newcodeinfo.h"
|
||||
#include "3ds/types.h"
|
||||
#include "loader.h"
|
||||
|
||||
Result svcOpenProcess(Handle* process, u32 processId);
|
||||
Result svcGetProcessId(u32* out, Handle handle);
|
||||
void svcBreak(u32 breakReason);
|
||||
|
||||
void loader_main (void)
|
||||
__attribute__((section (".loader")));
|
||||
|
||||
void loader_main(void)
|
||||
{
|
||||
Result res;
|
||||
|
||||
u32 address = NEWCODE_OFFSET;
|
||||
u32 neededMemory = (NEWCODE_SIZE + 0xFFF) & ~0xFFF; //rounding up
|
||||
|
||||
res = svcControlProcessMemory(getCurrentProcessHandle(), address, address, neededMemory, 6, 7);
|
||||
|
||||
if (res < 0)
|
||||
svcBreak(1);
|
||||
}
|
||||
|
||||
Handle getCurrentProcessHandle(void)
|
||||
{
|
||||
Handle handle = 0;
|
||||
u32 currentPid = 0;
|
||||
Result res;
|
||||
|
||||
svcGetProcessId(¤tPid, 0xffff8001);
|
||||
res = svcOpenProcess(&handle, currentPid);
|
||||
|
||||
if (res != 0)
|
||||
return 0;
|
||||
|
||||
return handle;
|
||||
}
|
57
src/includes/mappable.c
Normal file
57
src/includes/mappable.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Source
|
||||
https://github.com/devkitPro/libctru/blob/b18f04d88739283f6ffb55fe5ea77c73796cf61b/libctru/source/allocator/mappable.c
|
||||
*/
|
||||
|
||||
#include "3ds/allocator/mappable.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "3ds/result.h"
|
||||
|
||||
static u32 minAddr, maxAddr, currentAddr;
|
||||
|
||||
void mappableInit(u32 addrMin, u32 addrMax) {
|
||||
minAddr = addrMin;
|
||||
maxAddr = addrMax;
|
||||
currentAddr = minAddr;
|
||||
}
|
||||
|
||||
static u32 mappableFindAddressWithin(u32 start, u32 end, u32 size) {
|
||||
MemInfo info;
|
||||
PageInfo pgInfo;
|
||||
|
||||
u32 addr = start;
|
||||
while (addr >= start && (addr + size) < end && (addr + size) >= addr) {
|
||||
if (R_FAILED(svcQueryMemory(&info, &pgInfo, addr)))
|
||||
return 0;
|
||||
|
||||
if (info.state == MEMSTATE_FREE) {
|
||||
u32 sz = info.size - (addr - info.base_addr); // a free block might cover all the memory, etc.
|
||||
if (sz >= size)
|
||||
return addr;
|
||||
}
|
||||
|
||||
addr = info.base_addr + info.size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* mappableAlloc(size_t size) {
|
||||
// Round up, can only allocate in page units
|
||||
size = (size + 0xFFF) & ~0xFFF;
|
||||
|
||||
u32 addr = mappableFindAddressWithin(currentAddr, maxAddr, size);
|
||||
if (addr == 0) {
|
||||
// Need to rollover (maybe)
|
||||
addr = mappableFindAddressWithin(minAddr, currentAddr, size);
|
||||
if (addr == 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
currentAddr = addr + size >= maxAddr ? minAddr : addr + size;
|
||||
return (void*)addr;
|
||||
}
|
||||
|
||||
void mappableFree(void* mem) {
|
||||
(void)mem;
|
||||
}
|
801
src/includes/printf.c
Normal file
801
src/includes/printf.c
Normal file
@@ -0,0 +1,801 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources. These routines are thread
|
||||
// safe and reentrant!
|
||||
// Use this instead of the bloated standard/newlib printf cause these use
|
||||
// malloc for printf (and may not be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/printf.h"
|
||||
|
||||
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
||||
// printf_config.h header file
|
||||
// default: undefined
|
||||
#ifdef PRINTF_INCLUDE_CONFIG_H
|
||||
#include "printf_config.h"
|
||||
#endif
|
||||
|
||||
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// numeric number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_NTOA_BUFFER_SIZE
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// float number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_FTOA_BUFFER_SIZE
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// support for the floating point type (%f)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
#endif
|
||||
|
||||
// support for exponential floating point notation (%e/%g)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
|
||||
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif
|
||||
|
||||
// define the default floating point precision
|
||||
// default: 6 digits
|
||||
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
|
||||
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||
#endif
|
||||
|
||||
// define the largest float suitable to print with %f
|
||||
// default: 1e9
|
||||
#ifndef PRINTF_MAX_FLOAT
|
||||
#define PRINTF_MAX_FLOAT 1e9
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// internal flag definitions
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_UPPERCASE (1U << 5U)
|
||||
#define FLAGS_CHAR (1U << 6U)
|
||||
#define FLAGS_SHORT (1U << 7U)
|
||||
#define FLAGS_LONG (1U << 8U)
|
||||
#define FLAGS_PRECISION (1U << 10U)
|
||||
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
// output function type
|
||||
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||
|
||||
// wrapper (used as buffer) for output function type
|
||||
typedef struct {
|
||||
void (*fct)(char character, void* arg);
|
||||
void* arg;
|
||||
} out_fct_wrap_type;
|
||||
|
||||
// internal buffer output
|
||||
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) {
|
||||
if (idx < maxlen) {
|
||||
((char*)buffer)[idx] = character;
|
||||
}
|
||||
}
|
||||
|
||||
// internal null output
|
||||
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) {
|
||||
(void)character;
|
||||
(void)buffer;
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
}
|
||||
|
||||
// internal output function wrapper
|
||||
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) {
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
if (character) {
|
||||
// buffer is the output fct pointer
|
||||
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
|
||||
}
|
||||
}
|
||||
|
||||
// internal secure strlen
|
||||
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||
static inline unsigned int _strnlen_s(const char* str, size_t maxsize) {
|
||||
const char* s;
|
||||
for (s = str; *s && maxsize--; ++s)
|
||||
;
|
||||
return (unsigned int)(s - str);
|
||||
}
|
||||
|
||||
// internal test if char is a digit (0-9)
|
||||
// \return true if char is a digit
|
||||
static inline bool _is_digit(char ch) {
|
||||
return (ch >= '0') && (ch <= '9');
|
||||
}
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
static unsigned int _atoi(const char** str) {
|
||||
unsigned int i = 0U;
|
||||
while (_is_digit(**str)) {
|
||||
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// output the specified string in reverse, taking care of any zero-padding
|
||||
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len,
|
||||
unsigned int width, unsigned int flags) {
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad spaces up to given width
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
for (size_t i = len; i < width; i++) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
// reverse string
|
||||
while (len) {
|
||||
out(buf[--len], buffer, idx++, maxlen);
|
||||
}
|
||||
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len,
|
||||
bool negative, bool hex, unsigned int prec, unsigned int width, unsigned int flags) {
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && hex) {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if (hex && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
} else if (hex && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative,
|
||||
bool hex, unsigned int prec, unsigned int width, unsigned int flags) {
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
if (hex) {
|
||||
const char digit = (char)(value % 16U);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= 16U;
|
||||
} else {
|
||||
const char digit = (char)(value % 10U);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= 10U;
|
||||
}
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, hex, prec, width, flags);
|
||||
}
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec,
|
||||
unsigned int width, unsigned int flags);
|
||||
#endif
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec,
|
||||
unsigned int width, unsigned int flags) {
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||
if (value < -DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||
if (value > DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U,
|
||||
width, flags);
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing
|
||||
// your buffers == bad
|
||||
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
#else
|
||||
return 0U;
|
||||
#endif
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff < 0.5) {
|
||||
} else if ((frac == 0U) || (frac & 1U)) {
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
} else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec,
|
||||
unsigned int width, unsigned int flags) {
|
||||
// check for NaN and special values
|
||||
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
const bool negative = value < 0;
|
||||
if (negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// default precision
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
union {
|
||||
uint64_t U;
|
||||
double F;
|
||||
} conv;
|
||||
|
||||
conv.F = value;
|
||||
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see
|
||||
// https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.F) {
|
||||
expval--;
|
||||
conv.F /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (flags & FLAGS_ADAPT_EXP) {
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if ((value >= 1e-4) && (value < 1e6)) {
|
||||
if ((int)prec > expval) {
|
||||
prec = (unsigned)((int)prec - expval - 1);
|
||||
} else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0U;
|
||||
expval = 0;
|
||||
} else {
|
||||
// we use one sigfig for the whole part
|
||||
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||
--prec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will everything fit?
|
||||
unsigned int fwidth = width;
|
||||
if (width > minwidth) {
|
||||
// we didn't fall-back so subtract the characters required for the exponent
|
||||
fwidth -= minwidth;
|
||||
} else {
|
||||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0U;
|
||||
}
|
||||
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0U;
|
||||
}
|
||||
|
||||
// rescale the float value
|
||||
if (expval) {
|
||||
value /= conv.F;
|
||||
}
|
||||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth) {
|
||||
// output the exponential symbol
|
||||
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
// output the exponent value
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, false, 0, minwidth - 1,
|
||||
FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width)
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
// internal vsnprintf
|
||||
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) {
|
||||
unsigned int flags, width, precision, n;
|
||||
size_t idx = 0U;
|
||||
|
||||
if (!buffer) {
|
||||
// use null output function
|
||||
out = _out_null;
|
||||
}
|
||||
|
||||
while (*format) {
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
if (*format != '%') {
|
||||
// no
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
continue;
|
||||
} else {
|
||||
// yes, evaluate it
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate flags
|
||||
flags = 0U;
|
||||
do {
|
||||
switch (*format) {
|
||||
case '0':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '+':
|
||||
flags |= FLAGS_PLUS;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= FLAGS_SPACE;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '#':
|
||||
flags |= FLAGS_HASH;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
default:
|
||||
n = 0U;
|
||||
break;
|
||||
}
|
||||
} while (n);
|
||||
|
||||
// evaluate width field
|
||||
width = 0U;
|
||||
if (_is_digit(*format)) {
|
||||
width = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; // reverse padding
|
||||
width = (unsigned int)-w;
|
||||
} else {
|
||||
width = (unsigned int)w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate precision field
|
||||
precision = 0U;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (_is_digit(*format)) {
|
||||
precision = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
switch (*format) {
|
||||
case 'h':
|
||||
flags |= FLAGS_SHORT;
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
flags |= FLAGS_CHAR;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
case 'b': {
|
||||
// set the base
|
||||
// unsigned int base;
|
||||
bool hex;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
hex = true;
|
||||
}
|
||||
// else if (*format == 'o') {
|
||||
// base = 8U;
|
||||
// }
|
||||
// else if (*format == 'b') {
|
||||
// base = 2U;
|
||||
// }
|
||||
else {
|
||||
hex = false;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') {
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
}
|
||||
|
||||
// no plus or space flag for u, x, X, o, b
|
||||
if ((*format != 'i') && (*format != 'd')) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value),
|
||||
value < 0, hex, precision, width, flags);
|
||||
} else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int)
|
||||
: (flags & FLAGS_SHORT) ? (short int)va_arg(va, int)
|
||||
: va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value),
|
||||
value < 0, hex, precision, width, flags);
|
||||
}
|
||||
} else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, hex, precision,
|
||||
width, flags);
|
||||
} else {
|
||||
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int)
|
||||
: (flags & FLAGS_SHORT)
|
||||
? (unsigned short int)va_arg(va, unsigned int)
|
||||
: va_arg(va, unsigned int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, hex, precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (*format == 'F')
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g') || (*format == 'G'))
|
||||
flags |= FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E') || (*format == 'G'))
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
case 'c': {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char* p = va_arg(va, char*);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
l = (l < precision ? l : precision);
|
||||
}
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, true,
|
||||
precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%':
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default:
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int sprintf_(char* buffer, const char* format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) {
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const out_fct_wrap_type out_fct_wrap = { out, arg };
|
||||
const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
322
src/includes/srv.c
Normal file
322
src/includes/srv.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
srv.c _ Service manager.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "3ds/types.h"
|
||||
#include "3ds/result.h"
|
||||
#include "3ds/env.h"
|
||||
#include "3ds/srv.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "3ds/ipc.h"
|
||||
#include "3ds/synchronization.h"
|
||||
#include "3ds/os.h"
|
||||
#include "3ds/services/srvpm.h"
|
||||
|
||||
static Handle srvHandle;
|
||||
static int srvRefCount;
|
||||
|
||||
// static bool srvGetBlockingPolicy(void)
|
||||
// {
|
||||
// ThreadVars *tv = getThreadVars();
|
||||
// return tv->magic == THREADVARS_MAGIC && tv->srv_blocking_policy;
|
||||
// }
|
||||
|
||||
Result srvInit(void) {
|
||||
Result rc = 0;
|
||||
|
||||
if (AtomicPostIncrement(&srvRefCount))
|
||||
return 0;
|
||||
|
||||
if (osGetFirmVersion() < SYSTEM_VERSION(2, 39, 4) && *srvPmGetSessionHandle() != 0)
|
||||
rc = svcDuplicateHandle(&srvHandle,
|
||||
*srvPmGetSessionHandle()); // Prior to system version 7.0 srv:pm was a superset of srv:
|
||||
else
|
||||
rc = svcConnectToPort(&srvHandle, "srv:");
|
||||
if (R_FAILED(rc))
|
||||
goto end;
|
||||
|
||||
rc = srvRegisterClient();
|
||||
end:
|
||||
if (R_FAILED(rc))
|
||||
srvExit();
|
||||
return rc;
|
||||
}
|
||||
|
||||
void srvExit(void) {
|
||||
if (AtomicDecrement(&srvRefCount))
|
||||
return;
|
||||
|
||||
if (srvHandle != 0)
|
||||
svcCloseHandle(srvHandle);
|
||||
srvHandle = 0;
|
||||
}
|
||||
|
||||
// void srvSetBlockingPolicy(bool nonBlocking)
|
||||
// {
|
||||
// ThreadVars *tv = getThreadVars();
|
||||
// tv->srv_blocking_policy = nonBlocking;
|
||||
// }
|
||||
|
||||
Handle* srvGetSessionHandle(void) {
|
||||
return &srvHandle;
|
||||
}
|
||||
|
||||
Result srvGetServiceHandle(Handle* out, const char* name) {
|
||||
/* Look in service-list given to us by loader. If we find find a match,
|
||||
we return it. */
|
||||
Handle h = envGetHandle(name);
|
||||
|
||||
if (h != 0) {
|
||||
return svcDuplicateHandle(out, h);
|
||||
}
|
||||
|
||||
/* Normal request to service manager. */
|
||||
return srvGetServiceHandleDirect(out, name);
|
||||
}
|
||||
|
||||
Result srvRegisterClient(void) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x1, 0, 2); // 0x10002
|
||||
cmdbuf[1] = IPC_Desc_CurProcessId();
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvEnableNotification(Handle* semaphoreOut) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x2, 0, 0);
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
if (semaphoreOut)
|
||||
*semaphoreOut = cmdbuf[3];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvRegisterService(Handle* out, const char* name, int maxSessions) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x3, 4, 0); // 0x30100
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
cmdbuf[4] = maxSessions;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
if (out)
|
||||
*out = cmdbuf[3];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvUnregisterService(const char* name) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x4, 3, 0); // 0x400C0
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvGetServiceHandleDirect(Handle* out, const char* name) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x5, 4, 0); // 0x50100
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
// cmdbuf[4] = (u32)srvGetBlockingPolicy(); // per-thread setting, default is blocking
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
if (out)
|
||||
*out = cmdbuf[3];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvRegisterPort(const char* name, Handle clientHandle) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x6, 3, 2); // 0x600C2
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
cmdbuf[4] = IPC_Desc_SharedHandles(1);
|
||||
cmdbuf[5] = clientHandle;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvUnregisterPort(const char* name) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x7, 3, 0); // 0x700C0
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvGetPort(Handle* out, const char* name) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x8, 4, 0); // 0x80100
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
cmdbuf[4] = 0x0;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
if (out)
|
||||
*out = cmdbuf[3];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvWaitForPortRegistered(const char* name) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x8, 4, 0); // 0x80100
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
cmdbuf[4] = 0x1;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvSubscribe(u32 notificationId) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x9, 1, 0); // 0x90040
|
||||
cmdbuf[1] = notificationId;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvUnsubscribe(u32 notificationId) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xA, 1, 0); // 0xA0040
|
||||
cmdbuf[1] = notificationId;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvReceiveNotification(u32* notificationIdOut) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xB, 0, 0); // 0xB0000
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
if (notificationIdOut)
|
||||
*notificationIdOut = cmdbuf[2];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvPublishToSubscriber(u32 notificationId, u32 flags) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xC, 2, 0); // 0xC0080
|
||||
cmdbuf[1] = notificationId;
|
||||
cmdbuf[2] = flags;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvPublishAndGetSubscriber(u32* processIdCountOut, u32* processIdsOut, u32 notificationId) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xD, 1, 0); // 0xD0040
|
||||
cmdbuf[1] = notificationId;
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
if (processIdCountOut)
|
||||
*processIdCountOut = cmdbuf[2];
|
||||
if (processIdsOut)
|
||||
memcpy(processIdsOut, &cmdbuf[3], cmdbuf[2] * sizeof(u32));
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvIsServiceRegistered(bool* registeredOut, const char* name) {
|
||||
Result rc = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xE, 3, 0); // 0xE00C0
|
||||
strncpy((char*)&cmdbuf[1], name, 8);
|
||||
cmdbuf[3] = strnlen(name, 8);
|
||||
|
||||
if (R_FAILED(rc = svcSendSyncRequest(srvHandle)))
|
||||
return rc;
|
||||
|
||||
if (registeredOut)
|
||||
*registeredOut = cmdbuf[2] & 0xFF;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result srvIsPortRegistered(bool* registeredOut, const char* name) {
|
||||
Handle port;
|
||||
Result rc = srvGetPort(&port, name);
|
||||
|
||||
if (rc == 0xD8801BFA) {
|
||||
if (registeredOut)
|
||||
*registeredOut = false;
|
||||
return 0;
|
||||
} else if (R_SUCCEEDED(rc)) {
|
||||
if (registeredOut)
|
||||
*registeredOut = true;
|
||||
svcCloseHandle(port);
|
||||
}
|
||||
return rc;
|
||||
}
|
104
src/includes/srvpm.c
Normal file
104
src/includes/srvpm.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <stdlib.h>
|
||||
#include "3ds/types.h"
|
||||
#include "3ds/result.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "3ds/srv.h"
|
||||
#include "3ds/synchronization.h"
|
||||
#include "3ds/services/srvpm.h"
|
||||
#include "3ds/ipc.h"
|
||||
#include "3ds/os.h"
|
||||
|
||||
#define IS_PRE_7X (osGetFirmVersion() < SYSTEM_VERSION(2, 39, 4))
|
||||
|
||||
static Handle srvPmHandle;
|
||||
static int srvPmRefCount;
|
||||
|
||||
Result srvPmInit(void) {
|
||||
Result res = 0;
|
||||
|
||||
if (!IS_PRE_7X)
|
||||
res = srvInit();
|
||||
if (R_FAILED(res))
|
||||
return res;
|
||||
|
||||
if (AtomicPostIncrement(&srvPmRefCount))
|
||||
return 0;
|
||||
|
||||
if (!IS_PRE_7X)
|
||||
res = srvGetServiceHandleDirect(&srvPmHandle, "srv:pm");
|
||||
else {
|
||||
res = svcConnectToPort(&srvPmHandle, "srv:pm");
|
||||
if (R_SUCCEEDED(res))
|
||||
res = srvInit();
|
||||
}
|
||||
|
||||
if (R_FAILED(res))
|
||||
srvPmExit();
|
||||
return res;
|
||||
}
|
||||
|
||||
void srvPmExit(void) {
|
||||
if (*srvGetSessionHandle() != 0)
|
||||
srvExit();
|
||||
if (AtomicDecrement(&srvPmRefCount))
|
||||
return;
|
||||
if (srvPmHandle != 0)
|
||||
svcCloseHandle(srvPmHandle);
|
||||
srvPmHandle = 0;
|
||||
}
|
||||
|
||||
Handle* srvPmGetSessionHandle(void) {
|
||||
return &srvPmHandle;
|
||||
}
|
||||
|
||||
static Result srvPmSendCommand(u32* cmdbuf) {
|
||||
Result rc = 0;
|
||||
if (IS_PRE_7X)
|
||||
cmdbuf[0] |= 0x04000000;
|
||||
rc = svcSendSyncRequest(srvPmHandle);
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = cmdbuf[1];
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result SRVPM_PublishToProcess(u32 notificationId, Handle process) {
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x1, 1, 2); // 0x10042
|
||||
cmdbuf[1] = notificationId;
|
||||
cmdbuf[2] = IPC_Desc_SharedHandles(1);
|
||||
cmdbuf[3] = process;
|
||||
|
||||
return srvPmSendCommand(cmdbuf);
|
||||
}
|
||||
|
||||
Result SRVPM_PublishToAll(u32 notificationId) {
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x2, 1, 0); // 0x20040
|
||||
cmdbuf[1] = notificationId;
|
||||
|
||||
return srvPmSendCommand(cmdbuf);
|
||||
}
|
||||
|
||||
Result SRVPM_RegisterProcess(u32 pid, u32 count, const char (*serviceAccessControlList)[8]) {
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x3, 2, 2); // 0x30082
|
||||
cmdbuf[1] = pid;
|
||||
cmdbuf[2] = count * 2;
|
||||
cmdbuf[3] = IPC_Desc_StaticBuffer(count * 8, 0);
|
||||
cmdbuf[4] = (u32)serviceAccessControlList;
|
||||
|
||||
return srvPmSendCommand(cmdbuf);
|
||||
}
|
||||
|
||||
Result SRVPM_UnregisterProcess(u32 pid) {
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x4, 1, 0); // 0x40040
|
||||
cmdbuf[1] = pid;
|
||||
|
||||
return srvPmSendCommand(cmdbuf);
|
||||
}
|
52
src/includes/string.c
Normal file
52
src/includes/string.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "lib/types.h"
|
||||
#include <stdint.h>
|
||||
|
||||
size_t strlen(const char* str) {
|
||||
const char* s;
|
||||
for (s = str; *s; ++s)
|
||||
;
|
||||
return (s - str);
|
||||
}
|
||||
|
||||
void* memset(void* ptr, int value, size_t num) {
|
||||
char* s = ptr;
|
||||
while (num--)
|
||||
*s++ = value;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* memcpy(void* dst, const void* src, size_t len) {
|
||||
size_t i;
|
||||
if ((uintptr_t)dst % sizeof(long) == 0 && (uintptr_t)src % sizeof(long) == 0 && len % sizeof(long) == 0) {
|
||||
|
||||
long* d = dst;
|
||||
const long* s = src;
|
||||
|
||||
for (i = 0; i < len / sizeof(long); i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
} else {
|
||||
char* d = dst;
|
||||
const char* s = src;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t strnlen(const char* s, size_t max_len) {
|
||||
size_t i = 0;
|
||||
for (; (i < max_len) && s[i]; ++i)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
char* strncpy(char* dst, const char* src, size_t num) {
|
||||
char* b = dst;
|
||||
size_t i = 0;
|
||||
while (i++ != num && (*dst++ = *src++))
|
||||
;
|
||||
return b;
|
||||
}
|
658
src/includes/svc.s
Normal file
658
src/includes/svc.s
Normal file
@@ -0,0 +1,658 @@
|
||||
.arm
|
||||
.align 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 svcControlMemory
|
||||
push {r0, r4}
|
||||
ldr r0, [sp, #0x8]
|
||||
ldr r4, [sp, #0x8+0x4]
|
||||
svc 0x01
|
||||
ldr r2, [sp], #4
|
||||
str r1, [r2]
|
||||
ldr r4, [sp], #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcQueryMemory
|
||||
push {r0, r1, r4-r6}
|
||||
svc 0x02
|
||||
ldr r6, [sp]
|
||||
str r1, [r6]
|
||||
str r2, [r6, #4]
|
||||
str r3, [r6, #8]
|
||||
str r4, [r6, #0xc]
|
||||
ldr r6, [sp, #4]
|
||||
str r5, [r6]
|
||||
add sp, sp, #8
|
||||
pop {r4-r6}
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcExitProcess
|
||||
svc 0x03
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessAffinityMask
|
||||
svc 0x04
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetProcessAffinityMask
|
||||
svc 0x05
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessIdealProcessor
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x06
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetProcessIdealProcessor
|
||||
svc 0x07
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateThread
|
||||
push {r0, r4}
|
||||
ldr r0, [sp, #0x8]
|
||||
ldr r4, [sp, #0x8+0x4]
|
||||
svc 0x08
|
||||
ldr r2, [sp], #4
|
||||
str r1, [r2]
|
||||
ldr r4, [sp], #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcExitThread
|
||||
svc 0x09
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSleepThread
|
||||
svc 0x0A
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetThreadPriority
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x0B
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetThreadPriority
|
||||
svc 0x0C
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetThreadAffinityMask
|
||||
svc 0x0D
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetThreadAffinityMask
|
||||
svc 0x0E
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetThreadIdealProcessor
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x0F
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetThreadIdealProcessor
|
||||
svc 0x10
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessorID
|
||||
svc 0x11
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcRun
|
||||
push {r4,r5}
|
||||
ldr r2, [r1, #0x04]
|
||||
ldr r3, [r1, #0x08]
|
||||
ldr r4, [r1, #0x0C]
|
||||
ldr r5, [r1, #0x10]
|
||||
ldr r1, [r1, #0x00]
|
||||
svc 0x12
|
||||
pop {r4,r5}
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateMutex
|
||||
str r0, [sp, #-4]!
|
||||
svc 0x13
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcReleaseMutex
|
||||
svc 0x14
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateSemaphore
|
||||
push {r0}
|
||||
svc 0x15
|
||||
pop {r3}
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcReleaseSemaphore
|
||||
push {r0}
|
||||
svc 0x16
|
||||
pop {r3}
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateEvent
|
||||
str r0, [sp, #-4]!
|
||||
svc 0x17
|
||||
ldr r2, [sp], #4
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSignalEvent
|
||||
svc 0x18
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcClearEvent
|
||||
svc 0x19
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateTimer
|
||||
str r0, [sp, #-4]!
|
||||
svc 0x1A
|
||||
ldr r2, [sp], #4
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetTimer
|
||||
str r4, [sp, #-4]!
|
||||
ldr r1, [sp, #4]
|
||||
ldr r4, [sp, #8]
|
||||
svc 0x1B
|
||||
ldr r4, [sp], #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCancelTimer
|
||||
svc 0x1C
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcClearTimer
|
||||
svc 0x1D
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateMemoryBlock
|
||||
str r0, [sp, #-4]!
|
||||
ldr r0, [sp, #4]
|
||||
svc 0x1E
|
||||
ldr r2, [sp], #4
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcMapMemoryBlock
|
||||
svc 0x1F
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcUnmapMemoryBlock
|
||||
svc 0x20
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateAddressArbiter
|
||||
push {r0}
|
||||
svc 0x21
|
||||
pop {r2}
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcArbitrateAddress
|
||||
push {r4, r5}
|
||||
ldr r4, [sp, #8]
|
||||
ldr r5, [sp, #12]
|
||||
svc 0x22
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCloseHandle
|
||||
svc 0x23
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcWaitSynchronization
|
||||
svc 0x24
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcWaitSynchronizationN
|
||||
str r5, [sp, #-4]!
|
||||
str r4, [sp, #-4]!
|
||||
mov r5, r0
|
||||
ldr r0, [sp, #0x8]
|
||||
ldr r4, [sp, #0x8+0x4]
|
||||
svc 0x25
|
||||
str r1, [r5]
|
||||
ldr r4, [sp], #4
|
||||
ldr r5, [sp], #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcDuplicateHandle
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x27
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetSystemTick
|
||||
svc 0x28
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetHandleInfo
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x29
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
str r2, [r3,#4]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetSystemInfo
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x2A
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
str r2, [r3,#4]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessInfo
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x2B
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
str r2, [r3,#4]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetThreadInfo
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x2C
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
str r2, [r3,#4]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcConnectToPort
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x2D
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSendSyncRequest
|
||||
svc 0x32
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcOpenThread
|
||||
push {r0}
|
||||
svc 0x34
|
||||
pop {r2}
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessIdOfThread
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x36
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetThreadId
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x37
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetResourceLimit
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x38
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetResourceLimitLimitValues
|
||||
svc 0x39
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetResourceLimitCurrentValues
|
||||
svc 0x3A
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcOutputDebugString
|
||||
svc 0x3D
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreatePort
|
||||
push {r0, r1}
|
||||
svc 0x47
|
||||
ldr r3, [sp, #0]
|
||||
str r1, [r3]
|
||||
ldr r3, [sp, #4]
|
||||
str r2, [r3]
|
||||
add sp, sp, #8
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateSessionToPort
|
||||
push {r0}
|
||||
svc 0x48
|
||||
pop {r2}
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateSession
|
||||
push {r0, r1}
|
||||
svc 0x49
|
||||
ldr r3, [sp, #0]
|
||||
str r1, [r3]
|
||||
ldr r3, [sp, #4]
|
||||
str r2, [r3]
|
||||
add sp, sp, #8
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcAcceptSession
|
||||
str r0, [sp, #-4]!
|
||||
svc 0x4A
|
||||
ldr r2, [sp]
|
||||
str r1, [r2]
|
||||
add sp, sp, #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcReplyAndReceive
|
||||
str r0, [sp, #-4]!
|
||||
svc 0x4F
|
||||
ldr r2, [sp]
|
||||
str r1, [r2]
|
||||
add sp, sp, #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcBindInterrupt
|
||||
svc 0x50
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcUnbindInterrupt
|
||||
svc 0x51
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcInvalidateProcessDataCache
|
||||
svc 0x52
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcStoreProcessDataCache
|
||||
svc 0x53
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcFlushProcessDataCache
|
||||
svc 0x54
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcStartInterProcessDma
|
||||
stmfd sp!, {r0, r4, r5}
|
||||
ldr r0, [sp, #0xC]
|
||||
ldr r4, [sp, #0x10]
|
||||
ldr r5, [sp, #0x14]
|
||||
svc 0x55
|
||||
ldmfd sp!, {r2, r4, r5}
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcStopDma
|
||||
svc 0x56
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetDmaState
|
||||
str r0, [sp, #-4]!
|
||||
svc 0x57
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetGpuProt
|
||||
svc 0x59
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetWifiEnabled
|
||||
svc 0x5A
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcDebugActiveProcess
|
||||
push {r0}
|
||||
svc 0x60
|
||||
pop {r2}
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcBreakDebugProcess
|
||||
svc 0x61
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcTerminateDebugProcess
|
||||
svc 0x62
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessDebugEvent
|
||||
svc 0x63
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcContinueDebugEvent
|
||||
svc 0x64
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessList
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x65
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetThreadList
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x66
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetDebugThreadContext
|
||||
svc 0x67
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetDebugThreadContext
|
||||
svc 0x68
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcQueryDebugProcessMemory
|
||||
push {r0, r1, r4-r6}
|
||||
svc 0x69
|
||||
ldr r6, [sp]
|
||||
stm r6, {r1-r4}
|
||||
ldr r6, [sp, #4]
|
||||
str r5, [r6]
|
||||
add sp, sp, #8
|
||||
pop {r4-r6}
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcReadProcessMemory
|
||||
svc 0x6A
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcWriteProcessMemory
|
||||
svc 0x6B
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetHardwareBreakPoint
|
||||
svc 0x6C
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetDebugThreadParam
|
||||
push {r0, r1, r4, r5}
|
||||
ldr r0, [sp, #16]
|
||||
svc 0x6D
|
||||
pop {r4, r5}
|
||||
stm r4, {r1, r2}
|
||||
str r3, [r5]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcMapProcessMemory
|
||||
svc 0x71
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcUnmapProcessMemory
|
||||
svc 0x72
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateCodeSet
|
||||
str r0, [sp, #-0x4]!
|
||||
ldr r0, [sp, #4]
|
||||
svc 0x73
|
||||
ldr r2, [sp, #0]
|
||||
str r1, [r2]
|
||||
add sp, sp, #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateProcess
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x75
|
||||
ldr r2, [sp, #0]
|
||||
str r1, [r2]
|
||||
add sp, sp, #4
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcTerminateProcess
|
||||
svc 0x76
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetProcessResourceLimits
|
||||
svc 0x77
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateResourceLimit
|
||||
push {r0}
|
||||
svc 0x78
|
||||
pop {r2}
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetResourceLimitValues
|
||||
svc 0x79
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcBackdoor
|
||||
svc 0x7B
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcKernelSetState
|
||||
svc 0x7C
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcQueryProcessMemory
|
||||
push {r0, r1, r4-r6}
|
||||
svc 0x7D
|
||||
ldr r6, [sp]
|
||||
stm r6, {r1-r4}
|
||||
ldr r6, [sp, #4]
|
||||
str r5, [r6]
|
||||
add sp, sp, #8
|
||||
pop {r4-r6}
|
||||
bx lr
|
||||
SVC_END
|
45
src/includes/svc_loader.s
Normal file
45
src/includes/svc_loader.s
Normal file
@@ -0,0 +1,45 @@
|
||||
.arm
|
||||
.align 4
|
||||
|
||||
.macro SVC_BEGIN name
|
||||
.section .loader.\name, "ax", %progbits
|
||||
.global \name
|
||||
.type \name, %function
|
||||
.align 2
|
||||
.cfi_startproc
|
||||
\name:
|
||||
.endm
|
||||
|
||||
.macro SVC_END
|
||||
.cfi_endproc
|
||||
.endm
|
||||
|
||||
SVC_BEGIN svcOpenProcess
|
||||
push {r0}
|
||||
svc 0x33
|
||||
pop {r2}
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetProcessId
|
||||
str r0, [sp, #-0x4]!
|
||||
svc 0x35
|
||||
ldr r3, [sp], #4
|
||||
str r1, [r3]
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcBreak
|
||||
svc 0x3C
|
||||
bx lr
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcControlProcessMemory
|
||||
push {r4-r5}
|
||||
ldr r4, [sp, #0x8]
|
||||
ldr r5, [sp, #0xC]
|
||||
svc 0x70
|
||||
pop {r4-r5}
|
||||
bx lr
|
||||
SVC_END
|
224
src/includes/synchronization.c
Normal file
224
src/includes/synchronization.c
Normal file
@@ -0,0 +1,224 @@
|
||||
#include "3ds/types.h"
|
||||
#include "3ds/svc.h"
|
||||
#include "3ds/synchronization.h"
|
||||
|
||||
static Handle arbiter;
|
||||
|
||||
Result __sync_init(void) {
|
||||
return svcCreateAddressArbiter(&arbiter);
|
||||
}
|
||||
|
||||
void __sync_fini(void) {
|
||||
if (arbiter)
|
||||
svcCloseHandle(arbiter);
|
||||
}
|
||||
|
||||
Handle __sync_get_arbiter(void) {
|
||||
return arbiter;
|
||||
}
|
||||
|
||||
void LightLock_Init(LightLock* lock) {
|
||||
do
|
||||
__ldrex(lock);
|
||||
while (__strex(lock, 1));
|
||||
}
|
||||
|
||||
void LightLock_Lock(LightLock* lock) {
|
||||
s32 val;
|
||||
_begin:
|
||||
do {
|
||||
val = __ldrex(lock);
|
||||
if (val < 0) {
|
||||
// Add ourselves to the list of threads blocked on this lock
|
||||
if (__strex(lock, val - 1))
|
||||
goto _begin; // strex failed, try to lock again
|
||||
|
||||
_wait:
|
||||
// Wait for a thread to wake us up
|
||||
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
|
||||
|
||||
// Try to lock again
|
||||
do {
|
||||
val = __ldrex(lock);
|
||||
if (val < 0) {
|
||||
// Lock is still locked - keep waiting
|
||||
__clrex();
|
||||
goto _wait;
|
||||
}
|
||||
} while (__strex(lock, -(val - 1)));
|
||||
return;
|
||||
}
|
||||
} while (__strex(lock, -val));
|
||||
}
|
||||
|
||||
int LightLock_TryLock(LightLock* lock) {
|
||||
s32 val;
|
||||
do {
|
||||
val = __ldrex(lock);
|
||||
if (val < 0) {
|
||||
__clrex();
|
||||
return 1; // Failure
|
||||
}
|
||||
} while (__strex(lock, -val));
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
void LightLock_Unlock(LightLock* lock) {
|
||||
s32 val;
|
||||
do
|
||||
val = -__ldrex(lock);
|
||||
while (__strex(lock, val));
|
||||
|
||||
if (val > 1)
|
||||
// Wake up exactly one thread
|
||||
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0);
|
||||
}
|
||||
|
||||
void RecursiveLock_Init(RecursiveLock* lock) {
|
||||
LightLock_Init(&lock->lock);
|
||||
lock->thread_tag = 0;
|
||||
lock->counter = 0;
|
||||
}
|
||||
|
||||
void RecursiveLock_Lock(RecursiveLock* lock) {
|
||||
u32 tag = (u32)getThreadLocalStorage();
|
||||
if (lock->thread_tag != tag) {
|
||||
LightLock_Lock(&lock->lock);
|
||||
lock->thread_tag = tag;
|
||||
}
|
||||
lock->counter++;
|
||||
}
|
||||
|
||||
int RecursiveLock_TryLock(RecursiveLock* lock) {
|
||||
u32 tag = (u32)getThreadLocalStorage();
|
||||
if (lock->thread_tag != tag) {
|
||||
if (LightLock_TryLock(&lock->lock))
|
||||
return 1; // Failure
|
||||
lock->thread_tag = tag;
|
||||
}
|
||||
lock->counter++;
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
void RecursiveLock_Unlock(RecursiveLock* lock) {
|
||||
if (!--lock->counter) {
|
||||
lock->thread_tag = 0;
|
||||
LightLock_Unlock(&lock->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void LightEvent_SetState(LightEvent* event, int state) {
|
||||
do
|
||||
__ldrex(&event->state);
|
||||
while (__strex(&event->state, state));
|
||||
}
|
||||
|
||||
static inline int LightEvent_TryReset(LightEvent* event) {
|
||||
do {
|
||||
if (__ldrex(&event->state)) {
|
||||
__clrex();
|
||||
return 0;
|
||||
}
|
||||
} while (__strex(&event->state, -1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LightEvent_Init(LightEvent* event, ResetType reset_type) {
|
||||
LightLock_Init(&event->lock);
|
||||
LightEvent_SetState(event, reset_type == RESET_STICKY ? -2 : -1);
|
||||
}
|
||||
|
||||
void LightEvent_Clear(LightEvent* event) {
|
||||
if (event->state == 1) {
|
||||
LightLock_Lock(&event->lock);
|
||||
LightEvent_SetState(event, -2);
|
||||
LightLock_Unlock(&event->lock);
|
||||
} else if (event->state == 0)
|
||||
LightEvent_SetState(event, -1);
|
||||
}
|
||||
|
||||
void LightEvent_Pulse(LightEvent* event) {
|
||||
if (event->state == -2)
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
|
||||
else if (event->state == -1)
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
|
||||
else
|
||||
LightEvent_Clear(event);
|
||||
}
|
||||
|
||||
void LightEvent_Signal(LightEvent* event) {
|
||||
if (event->state == -1) {
|
||||
LightEvent_SetState(event, 0);
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
|
||||
} else if (event->state == -2) {
|
||||
LightLock_Lock(&event->lock);
|
||||
LightEvent_SetState(event, 1);
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
|
||||
LightLock_Unlock(&event->lock);
|
||||
}
|
||||
}
|
||||
|
||||
int LightEvent_TryWait(LightEvent* event) {
|
||||
if (event->state == 1)
|
||||
return 1;
|
||||
return LightEvent_TryReset(event);
|
||||
}
|
||||
|
||||
void LightEvent_Wait(LightEvent* event) {
|
||||
for (;;) {
|
||||
if (event->state == -2) {
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (event->state != -1) {
|
||||
if (event->state == 1)
|
||||
return;
|
||||
if (event->state == 0 && LightEvent_TryReset(event))
|
||||
return;
|
||||
}
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void LightSemaphore_Init(LightSemaphore* semaphore, s16 initial_count, s16 max_count) {
|
||||
semaphore->current_count = (s32)initial_count;
|
||||
semaphore->num_threads_acq = 0;
|
||||
semaphore->max_count = max_count;
|
||||
}
|
||||
|
||||
void LightSemaphore_Acquire(LightSemaphore* semaphore, s32 count) {
|
||||
s32 old_count;
|
||||
s16 num_threads_acq;
|
||||
|
||||
do {
|
||||
for (;;) {
|
||||
old_count = __ldrex(&semaphore->current_count);
|
||||
if (old_count > 0)
|
||||
break;
|
||||
__clrex();
|
||||
|
||||
do
|
||||
num_threads_acq = (s16)__ldrexh((u16*)&semaphore->num_threads_acq);
|
||||
while (__strexh((u16*)&semaphore->num_threads_acq, num_threads_acq + 1));
|
||||
|
||||
svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_WAIT_IF_LESS_THAN, count, 0);
|
||||
|
||||
do
|
||||
num_threads_acq = (s16)__ldrexh((u16*)&semaphore->num_threads_acq);
|
||||
while (__strexh((u16*)&semaphore->num_threads_acq, num_threads_acq - 1));
|
||||
}
|
||||
} while (__strex(&semaphore->current_count, old_count - count));
|
||||
}
|
||||
|
||||
void LightSemaphore_Release(LightSemaphore* semaphore, s32 count) {
|
||||
s32 old_count, new_count;
|
||||
do {
|
||||
old_count = __ldrex(&semaphore->current_count);
|
||||
new_count = old_count + count;
|
||||
if (new_count >= semaphore->max_count)
|
||||
new_count = semaphore->max_count;
|
||||
} while (__strex(&semaphore->current_count, new_count));
|
||||
|
||||
if (old_count <= 0 || semaphore->num_threads_acq > 0)
|
||||
svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_SIGNAL, count, 0);
|
||||
}
|
18
src/main.c
Normal file
18
src/main.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "input.h"
|
||||
#include "common.h"
|
||||
#include "z3D/z3D.h"
|
||||
#include "3ds/srv.h"
|
||||
#include "3ds/services/irrst.h"
|
||||
|
||||
GlobalContext* gGlobalContext;
|
||||
|
||||
void before_GlobalContext_Update(GlobalContext* globalCtx) {
|
||||
static u8 init = 0;
|
||||
if (!init) {
|
||||
srvInit();
|
||||
irrstInit();
|
||||
gGlobalContext = globalCtx;
|
||||
init = 1;
|
||||
}
|
||||
Input_Update();
|
||||
}
|
16
src/patches.s
Normal file
16
src/patches.s
Normal file
@@ -0,0 +1,16 @@
|
||||
.arm
|
||||
|
||||
.section .patch_before_GlobalContext_Update
|
||||
.global before_GlobalContext_Update_patch
|
||||
before_GlobalContext_Update_patch:
|
||||
bl hook_before_GlobalContext_Update
|
||||
|
||||
.section .patch_loader
|
||||
.global loader_patch
|
||||
loader_patch:
|
||||
b hook_into_loader
|
||||
|
||||
.section .patch_CameraUpdate
|
||||
.global CameraUpdate_patch
|
||||
CameraUpdate_patch:
|
||||
bl hook_CameraUpdate
|
Reference in New Issue
Block a user