1111
This commit is contained in:
commit
c1c6c7fe7f
|
|
@ -0,0 +1,6 @@
|
|||
MyGame.nro
|
||||
MyGame.nacp
|
||||
MyGame.lst
|
||||
MyGame.elf
|
||||
build/
|
||||
romfs/
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Switch",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/source/**",
|
||||
"${workspaceFolder}/source_game/**",
|
||||
"L:/Switch/devkitPro/devkitA64/aarch64-none-elf/include",
|
||||
"L:/Switch/devkitPro/libnx/include",
|
||||
"L:/Switch/devkitPro/portlibs/switch/include",
|
||||
"L:/Switch/devkitPro/portlibs/switch/include/SDL2"
|
||||
],
|
||||
"defines": [
|
||||
"__SWITCH__"
|
||||
],
|
||||
"compilerPath": "L:/Switch/devkitPro/devkitA64/bin/aarch64-none-elf-gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"configurationProvider": "ms-vscode.makefile-tools",
|
||||
"compilerArgs": [
|
||||
"-std=c++17",
|
||||
"-fno-rtti"
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"*.nut": "squirrel",
|
||||
"*.cpp": "cpp",
|
||||
"switch.h": "c",
|
||||
"squirrel.hpp": "c",
|
||||
"sdl.h": "c",
|
||||
"socket.h": "c",
|
||||
"requestscript.hpp": "c",
|
||||
"functional": "c",
|
||||
"locale.h": "c",
|
||||
"string.h": "c",
|
||||
"sqdbg.h": "c",
|
||||
"sstream": "cpp",
|
||||
"string_view": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"map": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"netfwd": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"span": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"text_encoding": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"valarray": "cpp",
|
||||
"variant": "cpp",
|
||||
"list": "cpp",
|
||||
"set": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"stdlib.h": "c",
|
||||
"json.hpp": "c",
|
||||
"stdio.h": "c",
|
||||
"strstream": "cpp",
|
||||
"barrier": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"complex": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"csetjmp": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cuchar": "cpp",
|
||||
"expected": "cpp",
|
||||
"regex": "cpp",
|
||||
"source_location": "cpp",
|
||||
"flat_map": "cpp",
|
||||
"flat_set": "cpp",
|
||||
"fstream": "cpp",
|
||||
"future": "cpp",
|
||||
"generator": "cpp",
|
||||
"latch": "cpp",
|
||||
"mutex": "cpp",
|
||||
"print": "cpp",
|
||||
"scoped_allocator": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"spanstream": "cpp",
|
||||
"stacktrace": "cpp",
|
||||
"stdfloat": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"syncstream": "cpp",
|
||||
"thread": "cpp",
|
||||
"typeindex": "cpp"
|
||||
},
|
||||
"Codegeex.RepoIndex": true
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_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
|
||||
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
||||
#
|
||||
# NO_ICON: if set to anything, do not use icon.
|
||||
# NO_NACP: if set to anything, no .nacp file is generated.
|
||||
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.jpg
|
||||
# - icon.jpg
|
||||
# - <libnx folder>/default_icon.jpg
|
||||
#
|
||||
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.json
|
||||
# - config.json
|
||||
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
|
||||
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
||||
# NACP building is skipped as well.
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
# SOURCES := source source/Tool source/squirrel source/EngineCore source/EngineFrame/Scene source/EngineFrame/Actor source/EngineFrame/Component source_game/Scene source_game/Global source_game/Asset
|
||||
SOURCES := $(shell find . -type f \( -name "*.c" -o -name "*.cpp" -o -name "*.s" \) -exec dirname {} \; | sort | uniq)
|
||||
DATA := data
|
||||
INCLUDES := include source source_game
|
||||
#ROMFS := romfs
|
||||
|
||||
APP_TITLE := MyProjectDemo
|
||||
APP_AUTHOR := Lenheart
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := `$(PREFIX)pkg-config --cflags sdl2 SDL2_mixer SDL2_image` -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++17 -fno-rtti
|
||||
# -fno-exceptions
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := `curl-config --libs` `$(PREFIX)pkg-config --libs sdl2 SDL2_mixer SDL2_image SDL2_ttf` \
|
||||
-lnx -lsquirrel_static -lsqstdlib_static -lstdc++ -lm
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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)))
|
||||
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_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
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 $(CONFIG_JSON)),)
|
||||
jsons := $(wildcard *.json)
|
||||
ifneq (,$(findstring $(TARGET).json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/$(TARGET).json
|
||||
else
|
||||
ifneq (,$(findstring config.json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/config.json
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.jpg)
|
||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||
else
|
||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||
endif
|
||||
|
||||
ifneq ($(APP_TITLEID),)
|
||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
else
|
||||
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||
endif
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
|
||||
all : $(OUTPUT).nro
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
all : $(OUTPUT).nsp
|
||||
|
||||
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||
|
||||
$(OUTPUT).nso : $(OUTPUT).elf
|
||||
|
||||
endif
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
|
@ -0,0 +1 @@
|
|||
print("松鼠脚本系统加载成功!");
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
文件名:UiRender.nut
|
||||
路径:Core/UiRender.nut
|
||||
创建日期:2025-09-07 19:01
|
||||
文件用途:
|
||||
*/
|
||||
currentAngle <- 0;
|
||||
|
||||
|
||||
function UI_Render(dt) {
|
||||
|
||||
|
||||
// // print("ui渲染");
|
||||
|
||||
// SDL.DrawImg("sprite/interface2/nowloading/nowloading.img", 1, 0, 0);
|
||||
// SDL.DrawImg("sprite/interface2/nowloading/nowloading.img", 0, 0, 720 - 34);
|
||||
|
||||
// if(!getroottable().rawin("Img1")) Img1 <- SDL.CreateTexture("sprite/interface2/nowloading/nowloading.img", 1);
|
||||
// if(!getroottable().rawin("Img2")) Img2 <- SDL.CreateTexture("sprite/interface2/nowloading/nowloading.img", 0);
|
||||
|
||||
// SDL.DrawImg(Img1, 0, 0, 1280, 720);
|
||||
// SDL.DrawImg(Img2, 0, 720 - 34, 1280, 34);
|
||||
|
||||
|
||||
// local Speed = 180.0;
|
||||
// currentAngle += Speed * dt;
|
||||
// currentAngle = currentAngle % 360.0;
|
||||
// // print(dt);
|
||||
// SDL.DrawImgEx("sprite/interface2/nowloading/nowloading.img", 4, 617, 600, 2, currentAngle);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"Files": [
|
||||
"Core/Eunm.nut",
|
||||
"Core/UiRender.nut",
|
||||
"main.nut"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
function main() {
|
||||
|
||||
|
||||
print("松鼠脚本 Main 函数执行!");
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"source/EngineCore": {
|
||||
"description": "引擎核心类"
|
||||
},
|
||||
"source/EngineCore/Scene.h": {
|
||||
"description": "场景类"
|
||||
},
|
||||
"source/EngineCore/Game.h": {
|
||||
"description": "游戏主类"
|
||||
},
|
||||
"source/EngineCore/Scene_Base.h": {
|
||||
"description": "场景基类"
|
||||
},
|
||||
"source/EngineFrame": {
|
||||
"description": "引擎框架类"
|
||||
},
|
||||
"source/EngineCore/IntrusiveList.hpp": {
|
||||
"description": "侵入式链表"
|
||||
},
|
||||
"source/Tool/Tool_Network.h": {
|
||||
"description": "网络请求工具"
|
||||
},
|
||||
"source/Tool/RemoteLogger.h": {
|
||||
"description": "日志系统"
|
||||
},
|
||||
"source/squirrel/SquirrelEx.h": {
|
||||
"description": "松鼠系统"
|
||||
},
|
||||
"source/EngineFrame/Actor": {
|
||||
"description": "演员系统"
|
||||
},
|
||||
"source/EngineFrame/Component": {
|
||||
"description": "组件系统"
|
||||
},
|
||||
"source/EngineFrame/Scene": {
|
||||
"description": "场景系统"
|
||||
},
|
||||
"source/Tool/RefPtr.h": {
|
||||
"description": "引用计数智能指针"
|
||||
},
|
||||
"source/Tool/RefObject.h": {
|
||||
"description": "引用计数对象"
|
||||
},
|
||||
"source/Tool/Allocator.h": {
|
||||
"description": "内存分配器"
|
||||
},
|
||||
"source/Tool/Common.h": {
|
||||
"description": "通用对象类型"
|
||||
},
|
||||
"source/Tool/RefBasePtr.hpp": {
|
||||
"description": "引用计数基础指针"
|
||||
},
|
||||
"source/Tool/Ifstream_NPK.h": {
|
||||
"description": "自定义读取流"
|
||||
},
|
||||
"source_game/Scene": {
|
||||
"description": "游戏场景"
|
||||
},
|
||||
"source_game/Actor/Actor_UI.h": {
|
||||
"description": "ui角色"
|
||||
},
|
||||
"source_game/Global": {
|
||||
"description": "全局相关"
|
||||
},
|
||||
"source_game/Scene/Scene_Loading_UI.h": {
|
||||
"description": "加载界面UI"
|
||||
},
|
||||
"source/EngineFrame/Component/Text.h": {
|
||||
"description": "文字"
|
||||
},
|
||||
"source/EngineFrame/Component/Sprite.h": {
|
||||
"description": "图像"
|
||||
},
|
||||
"source_game/Asset": {
|
||||
"description": "资源"
|
||||
},
|
||||
"source_game/Asset/AnimationStruct.h": {
|
||||
"description": "Ani结构数据"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
#include "Asset_ImagePack.h"
|
||||
|
||||
Asset_ImagePack::Asset_ImagePack()
|
||||
{
|
||||
}
|
||||
Asset_ImagePack::~Asset_ImagePack()
|
||||
{
|
||||
}
|
||||
|
||||
void Asset_ImagePack::Init()
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
std::string path = "ImagePacks2/";
|
||||
dir = opendir(path.c_str());
|
||||
|
||||
while ((ent = readdir(dir)))
|
||||
{
|
||||
// 跳过.和..目录
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
std::string RealPath = path + ent->d_name;
|
||||
Ifstream_NPK Fs;
|
||||
Fs.open(RealPath.c_str(), std::ios::in | std::ios::binary);
|
||||
if (Fs.is_open())
|
||||
{
|
||||
std::string Header = Fs.ReadString();
|
||||
// 如果是NPK
|
||||
if (Header.find("NeoplePack_Bill") != std::string::npos)
|
||||
{
|
||||
// 读取img数量
|
||||
int ImageCount = Fs.ReadInt();
|
||||
// 读取头
|
||||
NpkInfo *ImgList = new NpkInfo[ImageCount];
|
||||
for (int i = 0; i < ImageCount; i++)
|
||||
{
|
||||
ImgList[i].Offset = Fs.ReadInt();
|
||||
ImgList[i].Length = Fs.ReadInt();
|
||||
ImgList[i].Path = Fs.ReadInfo();
|
||||
}
|
||||
for (int i = 0; i < ImageCount; i++)
|
||||
{
|
||||
IMG img;
|
||||
img.imgOffset = ImgList[i].Offset;
|
||||
img.imgSize = ImgList[i].Length;
|
||||
img.img_index = i;
|
||||
img.lpBelongsFile = ent->d_name;
|
||||
img.lpImgName = ImgList[i].Path;
|
||||
img.lp_lplist = NULL;
|
||||
img.png_sum = 0;
|
||||
|
||||
map_npk.insert(make_pair(img.lpImgName, img));
|
||||
}
|
||||
// 销毁
|
||||
delete[] ImgList;
|
||||
}
|
||||
}
|
||||
Fs.close();
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void Asset_ImagePack::ParseColor(BYTE *Tab, int Type, BYTE *SaveByte, int Offset)
|
||||
{
|
||||
BYTE a = 0;
|
||||
BYTE r = 0;
|
||||
BYTE g = 0;
|
||||
BYTE b = 0;
|
||||
switch (Type)
|
||||
{
|
||||
case 0x0e:
|
||||
a = (BYTE)(Tab[1] >> 7);
|
||||
r = (BYTE)((Tab[1] >> 2) & 0x1f);
|
||||
g = (BYTE)((Tab[0] >> 5) | ((Tab[1] & 3) << 3));
|
||||
b = (BYTE)(Tab[0] & 0x1f);
|
||||
a = (BYTE)(a * 0xff);
|
||||
r = (BYTE)((r << 3) | (r >> 2));
|
||||
g = (BYTE)((g << 3) | (g >> 2));
|
||||
b = (BYTE)((b << 3) | (b >> 2));
|
||||
break;
|
||||
case 0x0f:
|
||||
a = (BYTE)(Tab[1] & 0xf0);
|
||||
r = (BYTE)((Tab[1] & 0xf) << 4);
|
||||
g = (BYTE)(Tab[0] & 0xf0);
|
||||
b = (BYTE)((Tab[0] & 0xf) << 4);
|
||||
break;
|
||||
}
|
||||
SaveByte[Offset + 0] = b;
|
||||
SaveByte[Offset + 1] = g;
|
||||
SaveByte[Offset + 2] = r;
|
||||
SaveByte[Offset + 3] = a;
|
||||
}
|
||||
|
||||
void Asset_ImagePack::LoadImgToMem(IMG *p)
|
||||
{
|
||||
std::string Path = "ImagePacks2/" + p->lpBelongsFile;
|
||||
// SDL_Log("LoadImgToMem : %s", Path.c_str());
|
||||
Ifstream_NPK Fs;
|
||||
Fs.open(Path.c_str(), std::ios::in | std::ios::binary);
|
||||
if (Fs.is_open())
|
||||
{
|
||||
Fs.seekg(p->imgOffset);
|
||||
std::string Flag = Fs.ReadString(); // 读取Flag
|
||||
if (Flag.find("Neople Img File") != std::string::npos)
|
||||
{
|
||||
// 索引表大小
|
||||
long TableLength = Fs.ReadLong();
|
||||
// img 版本 4字节
|
||||
Fs.ReadInt(); // 读取版本
|
||||
// img 帧数
|
||||
int IndexCount = Fs.ReadInt();
|
||||
// 图片数量赋值
|
||||
p->png_sum = IndexCount;
|
||||
|
||||
// new出 Png数量的 结构体
|
||||
ImgInfo *PngList = new ImgInfo[IndexCount];
|
||||
|
||||
for (int i = 0; i < IndexCount; i++)
|
||||
{
|
||||
PngList[i].Type = Fs.ReadInt();
|
||||
if (PngList[i].Type == 17)
|
||||
{
|
||||
// 引用贴图
|
||||
int frbuf = Fs.ReadInt();
|
||||
// 压缩类型 用来临时存一下引用编号
|
||||
PngList[i].CmpType = frbuf;
|
||||
////大小
|
||||
PngList[i].Size = 0;
|
||||
PngList[i].Offset = PngList[i - 1].Offset + PngList[i - 1].Size;
|
||||
continue;
|
||||
}
|
||||
// 压缩类型
|
||||
PngList[i].CmpType = Fs.ReadInt();
|
||||
// 宽度
|
||||
PngList[i].Width = Fs.ReadInt();
|
||||
// 高度
|
||||
PngList[i].Height = Fs.ReadInt();
|
||||
// 大小
|
||||
PngList[i].Size = Fs.ReadInt();
|
||||
// Xpos
|
||||
PngList[i].Xpos = Fs.ReadInt();
|
||||
// Ypos
|
||||
PngList[i].Ypos = Fs.ReadInt();
|
||||
// 帧域X
|
||||
PngList[i].FrameXpos = Fs.ReadInt();
|
||||
// 帧域Y
|
||||
PngList[i].FrameYpos = Fs.ReadInt();
|
||||
// 计算偏移
|
||||
if (i == 0)
|
||||
PngList[i].Offset = 0 + p->imgOffset + TableLength + 32;
|
||||
else
|
||||
PngList[i].Offset = PngList[i - 1].Offset + PngList[i - 1].Size;
|
||||
}
|
||||
|
||||
for (int i = 0; i < IndexCount; i++)
|
||||
{
|
||||
// 引用
|
||||
if (PngList[i].Type == 17)
|
||||
{
|
||||
// 引用编号
|
||||
int YYIndex = PngList[i].CmpType;
|
||||
int sizebuf = PngList[YYIndex].Width * PngList[YYIndex].Height * 4;
|
||||
BYTE *bByte = new BYTE[sizebuf];
|
||||
memcpy(bByte, PngList[PngList[i].CmpType].PNGdata, sizebuf);
|
||||
PngList[i].PNGdata = PngList[YYIndex].PNGdata;
|
||||
|
||||
// 压缩类型 用来临时存一下引用编号
|
||||
PngList[i].CmpType = PngList[YYIndex].CmpType;
|
||||
// 宽度
|
||||
PngList[i].Width = PngList[YYIndex].Width;
|
||||
// 高度
|
||||
PngList[i].Height = PngList[YYIndex].Height;
|
||||
// 大小
|
||||
PngList[i].Size = 0;
|
||||
// Xpos
|
||||
PngList[i].Xpos = PngList[YYIndex].Xpos;
|
||||
// Ypos
|
||||
PngList[i].Ypos = PngList[YYIndex].Ypos;
|
||||
// 帧域X
|
||||
PngList[i].FrameXpos = PngList[YYIndex].FrameXpos;
|
||||
// 帧域Y
|
||||
PngList[i].FrameYpos = PngList[YYIndex].FrameYpos;
|
||||
continue;
|
||||
}
|
||||
|
||||
Fs.seekg(PngList[i].Offset);
|
||||
BYTE *PngData = Fs.ReadCustomSize(PngList[i].Size);
|
||||
int DeSize = PngList[i].Width * PngList[i].Height * 4;
|
||||
BYTE *bByte = new BYTE[DeSize];
|
||||
unsigned long RealSize = DeSize;
|
||||
uncompress(bByte, &RealSize, PngData, (unsigned long)PngList[i].Size);
|
||||
delete[] PngData;
|
||||
|
||||
if (PngList[i].Type != 16)
|
||||
{
|
||||
int PngByteSize = DeSize * 2;
|
||||
PngList[i].PNGdata = new BYTE[PngByteSize];
|
||||
|
||||
for (int e = 0; e < PngByteSize; e += 4)
|
||||
{
|
||||
BYTE NeedData[2];
|
||||
memset(NeedData, 0, 2);
|
||||
memcpy(NeedData, bByte + (e / 4) * 2, 2);
|
||||
ParseColor(NeedData, PngList[i].Type, PngList[i].PNGdata, e);
|
||||
}
|
||||
delete[] bByte;
|
||||
}
|
||||
else
|
||||
{
|
||||
PngList[i].PNGdata = bByte;
|
||||
}
|
||||
}
|
||||
|
||||
p->lp_lplist = PngList;
|
||||
}
|
||||
else if (Flag.find("Neople Image File") != std::string::npos)
|
||||
{
|
||||
// LoadImgToMem2(p);
|
||||
}
|
||||
Fs.close();
|
||||
}
|
||||
}
|
||||
|
||||
Asset_ImagePack::IMG *Asset_ImagePack::GetIMG(std::string imgName)
|
||||
{
|
||||
IMG *img = NULL;
|
||||
std::map<std::string, IMG>::iterator itr;
|
||||
itr = map_npk.find(imgName);
|
||||
if (itr == map_npk.end())
|
||||
{
|
||||
std::string mes = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!调用了不存在的Img : " + imgName;
|
||||
SDL_Log(mes.c_str());
|
||||
img = &map_npk["sprite/interface/base.img"];
|
||||
}
|
||||
else
|
||||
{
|
||||
img = &itr->second;
|
||||
}
|
||||
// 如果图片数组不存在 或者 图片数据不存在都要重读
|
||||
if (!img->lp_lplist)
|
||||
{
|
||||
LoadImgToMem(img);
|
||||
}
|
||||
img->UseTime = SDL_GetTicks();
|
||||
return img;
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <SDL.h>
|
||||
#include <map>
|
||||
|
||||
#include "Tool/Ifstream_NPK.h"
|
||||
#include <zlib.h>
|
||||
|
||||
class Asset_ImagePack
|
||||
{
|
||||
public:
|
||||
struct NpkInfo
|
||||
{
|
||||
int Offset;
|
||||
int Length;
|
||||
std::string Path;
|
||||
};
|
||||
|
||||
// PNG结构体
|
||||
struct ImgInfo
|
||||
{
|
||||
// 图片格式
|
||||
int Type;
|
||||
// 压缩类型
|
||||
int CmpType;
|
||||
// 宽度
|
||||
int Width;
|
||||
// 高度
|
||||
int Height;
|
||||
// 大小
|
||||
int Size;
|
||||
// Xpos
|
||||
int Xpos;
|
||||
// Ypos
|
||||
int Ypos;
|
||||
// Xpos
|
||||
int XposEx = 0;
|
||||
// Ypos
|
||||
int YposEx = 0;
|
||||
// 帧域X
|
||||
int FrameXpos;
|
||||
// 帧域Y
|
||||
int FrameYpos;
|
||||
// 偏移
|
||||
int Offset;
|
||||
// Png位图数据
|
||||
BYTE *PNGdata;
|
||||
};
|
||||
|
||||
struct IMG // npk的img的结构体
|
||||
{
|
||||
std::string lpImgName; // img文件的路径
|
||||
int img_index; // img文件在npk文件里的序号
|
||||
unsigned imgOffset;
|
||||
unsigned imgSize;
|
||||
std::string lpBelongsFile; // 这个img属于哪个npk文件
|
||||
int png_sum; // 这个img文件有多少个 图片
|
||||
ImgInfo *lp_lplist; // 图片的数组..
|
||||
Uint32 UseTime = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
Asset_ImagePack(const Asset_ImagePack &) = delete;
|
||||
Asset_ImagePack &operator=(const Asset_ImagePack &) = delete;
|
||||
Asset_ImagePack(Asset_ImagePack &&) = delete;
|
||||
Asset_ImagePack &operator=(Asset_ImagePack &&) = delete;
|
||||
// 全局访问点
|
||||
static Asset_ImagePack &GetInstance()
|
||||
{
|
||||
static Asset_ImagePack instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
public:
|
||||
void Init();
|
||||
void ParseColor(BYTE *Tab, int Type, BYTE *SaveByte, int Offset);
|
||||
void LoadImgToMem(IMG *p);
|
||||
IMG *GetIMG(std::string imgName);
|
||||
|
||||
private:
|
||||
Asset_ImagePack(/* args */);
|
||||
~Asset_ImagePack();
|
||||
|
||||
std::map<std::string, IMG> map_npk;
|
||||
};
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
#include "EngineCore/Asset_Script.h"
|
||||
#include "Asset_Script.h"
|
||||
|
||||
void Asset_Script::Init()
|
||||
{
|
||||
// 读取头建立树
|
||||
InitHeader();
|
||||
// 读取bin文件
|
||||
InitBin();
|
||||
// 读取LoadString
|
||||
InitLoadString();
|
||||
|
||||
InitFlag = true;
|
||||
}
|
||||
|
||||
void Asset_Script::Clear()
|
||||
{
|
||||
FileInfo.clear();
|
||||
BinStringM.clear();
|
||||
LoadStringM.clear();
|
||||
_Data.clear();
|
||||
_Data.shrink_to_fit();
|
||||
InitFlag = false;
|
||||
}
|
||||
|
||||
void Asset_Script::InitHeader()
|
||||
{
|
||||
// 读取UUID的长度
|
||||
int UUID_LENGTH = GetInt();
|
||||
// UUID 读 1 - 36位 构造 UTF8 string
|
||||
std::string UUID = GetString(UUID_LENGTH);
|
||||
// 版本号
|
||||
int Version = GetInt();
|
||||
(void)Version;
|
||||
// 文件路径数据的大小
|
||||
int AlignedIndexHeaderSize = GetInt();
|
||||
// 解密密钥
|
||||
int IndexHeaderCrc = GetInt();
|
||||
// 文件数量
|
||||
int IndexSize = GetInt();
|
||||
// 文件起始位置
|
||||
int FristPos = tellg();
|
||||
CrcDecode(AlignedIndexHeaderSize, IndexHeaderCrc);
|
||||
int CurrPos = 0;
|
||||
StartPos = AlignedIndexHeaderSize + 56;
|
||||
// 建立pvf文件索引表
|
||||
for (int i = 0; i < IndexSize; i++)
|
||||
{
|
||||
seek(FristPos + CurrPos);
|
||||
int FileNumber = GetInt();
|
||||
(void)FileNumber;
|
||||
int FilePathLength = GetInt();
|
||||
std::string FileName = tolower(GetString(FilePathLength));
|
||||
int FileLength = GetInt();
|
||||
int Cre32 = GetInt();
|
||||
int RelativeOffset = GetInt();
|
||||
if (FileLength > 0)
|
||||
{
|
||||
int RealFileLength = (FileLength + 3) & 4294967292;
|
||||
PvfFileInfo Info;
|
||||
Info.ROffset = RelativeOffset;
|
||||
Info.Cr32 = Cre32;
|
||||
Info.Length = RealFileLength;
|
||||
Info.DecodeFlag = false;
|
||||
FileInfo[FileName] = Info;
|
||||
}
|
||||
CurrPos += 20;
|
||||
CurrPos += FilePathLength;
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_Script::InitBin()
|
||||
{
|
||||
if (FileInfo.count("stringtable.bin") == 0)
|
||||
{
|
||||
SDL_LogError(0, "stringtable.bin文件不存在");
|
||||
return;
|
||||
}
|
||||
PvfFileInfo BinInfo = FileInfo["stringtable.bin"];
|
||||
seek(StartPos + BinInfo.ROffset);
|
||||
CrcDecode(BinInfo.Length, BinInfo.Cr32);
|
||||
seek(StartPos + BinInfo.ROffset);
|
||||
int FileHPos = tellg();
|
||||
int Count = GetInt();
|
||||
int CurrentIndex = 0;
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
seek(FileHPos + CurrentIndex * 4 + 4);
|
||||
int StartPos = GetInt();
|
||||
int EndPos = GetInt();
|
||||
int Len = EndPos - StartPos;
|
||||
seek(FileHPos + StartPos + 4);
|
||||
std::string Str = GetString(Len);
|
||||
BinStringM[CurrentIndex] = Str;
|
||||
CurrentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_Script::InitLoadString()
|
||||
{
|
||||
if (FileInfo.count("n_string.lst") == 0)
|
||||
{
|
||||
SDL_LogError(0, "n_string.lst文件不存在");
|
||||
}
|
||||
PvfFileInfo Info = FileInfo["n_string.lst"];
|
||||
seek(StartPos + Info.ROffset);
|
||||
CrcDecode(Info.Length, Info.Cr32);
|
||||
seek(StartPos + Info.ROffset);
|
||||
|
||||
int FileHPos = tellg();
|
||||
int Flag = GetShort();
|
||||
(void)Flag;
|
||||
int i = 2;
|
||||
while (i < Info.Length)
|
||||
{
|
||||
if ((Info.Length - i) >= 10)
|
||||
{
|
||||
seek(FileHPos + i + 6);
|
||||
int FindKey = GetInt();
|
||||
std::string Key = GetBinString(FindKey);
|
||||
std::string Type = tolower(Key.substr(0, Key.find("/")));
|
||||
if (Key.length() > 0)
|
||||
{
|
||||
PvfFileInfo *FileInfo = GetFileInfo(Key);
|
||||
if (FileInfo == nullptr)
|
||||
continue;
|
||||
|
||||
seek(StartPos + FileInfo->ROffset);
|
||||
CrcDecode(FileInfo->Length, FileInfo->Cr32);
|
||||
seek(StartPos + FileInfo->ROffset);
|
||||
|
||||
std::string Str = GetStringNormal(FileInfo->Length);
|
||||
std::vector<std::string> StrArr = split(Str, "\n");
|
||||
for (auto it = StrArr.begin(); it != StrArr.end(); ++it)
|
||||
{
|
||||
std::string strobj = *it;
|
||||
if (strobj.find(">") != std::string::npos)
|
||||
{
|
||||
std::vector<std::string> strobjarr = split(strobj, ">");
|
||||
if (strobjarr.size() > 1)
|
||||
{
|
||||
LoadStringM[Type][strobjarr[0]] = strobjarr[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
i += 10;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Asset_Script::GetBinString(int Key)
|
||||
{
|
||||
if (BinStringM.count(Key))
|
||||
return BinStringM[Key];
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string Asset_Script::GetLoadString(std::string Type, std::string Key)
|
||||
{
|
||||
if (LoadStringM.count(Type) && LoadStringM[Type].count(Key))
|
||||
return LoadStringM[Type][Key];
|
||||
return "";
|
||||
}
|
||||
|
||||
Asset_Script::PvfFileInfo *Asset_Script::GetFileInfo(std::string path)
|
||||
{
|
||||
path = tolower(path);
|
||||
if (FileInfo.count(path))
|
||||
return &FileInfo[path];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string Asset_Script::GetFileContent(std::string path)
|
||||
{
|
||||
if (FileInfo.count(path))
|
||||
{
|
||||
seek(StartPos + FileInfo[path].ROffset);
|
||||
if (FileInfo[path].DecodeFlag == false)
|
||||
{
|
||||
CrcDecode(FileInfo[path].Length, FileInfo[path].Cr32);
|
||||
seek(StartPos + FileInfo[path].ROffset);
|
||||
FileInfo[path].DecodeFlag = true;
|
||||
}
|
||||
char *blobp = new char[FileInfo[path].Length];
|
||||
read((char *)blobp, FileInfo[path].Length);
|
||||
std::string Str(blobp);
|
||||
delete[] blobp;
|
||||
return Str;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::vector<BYTE> Asset_Script::GetFileContentByte(std::string path)
|
||||
{
|
||||
if (FileInfo.count(path))
|
||||
{
|
||||
seek(StartPos + FileInfo[path].ROffset);
|
||||
if (FileInfo[path].DecodeFlag == false)
|
||||
{
|
||||
CrcDecode(FileInfo[path].Length, FileInfo[path].Cr32);
|
||||
seek(StartPos + FileInfo[path].ROffset);
|
||||
FileInfo[path].DecodeFlag = true;
|
||||
}
|
||||
std::vector<BYTE> blobp(FileInfo[path].Length);
|
||||
read((char *)blobp.data(), FileInfo[path].Length);
|
||||
return blobp;
|
||||
}
|
||||
return std::vector<BYTE>();
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <dirent.h>
|
||||
#include <SDL.h>
|
||||
#include <map>
|
||||
|
||||
#include "Tool/Ifstream_PVF.h"
|
||||
|
||||
class Asset_Script : public Ifstream_PVF
|
||||
{
|
||||
public:
|
||||
struct PvfFileInfo
|
||||
{
|
||||
int ROffset;
|
||||
int Cr32;
|
||||
int Length;
|
||||
bool DecodeFlag = false;
|
||||
};
|
||||
|
||||
private:
|
||||
Asset_Script(const std::string filename = "Script.pvf") : Ifstream_PVF(filename) {};
|
||||
~Asset_Script() = default;
|
||||
|
||||
int StartPos = 0;
|
||||
std::map<std::string, PvfFileInfo> FileInfo;
|
||||
std::map<int, std::string> BinStringM;
|
||||
std::map<std::string, std::map<std::string, std::string>> LoadStringM;
|
||||
|
||||
public:
|
||||
Asset_Script(const Asset_Script &) = delete;
|
||||
Asset_Script &operator=(const Asset_Script &) = delete;
|
||||
Asset_Script(Asset_Script &&) = delete;
|
||||
Asset_Script &operator=(Asset_Script &&) = delete;
|
||||
// 全局访问点
|
||||
static Asset_Script &GetInstance()
|
||||
{
|
||||
static Asset_Script instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
public:
|
||||
void Init();
|
||||
void InitHeader();
|
||||
void InitBin();
|
||||
void InitLoadString();
|
||||
void Clear();
|
||||
|
||||
public:
|
||||
std::string
|
||||
GetBinString(int Key);
|
||||
std::string GetLoadString(std::string Type, std::string Key);
|
||||
PvfFileInfo *GetFileInfo(std::string path);
|
||||
|
||||
std::string GetFileContent(std::string path); // 获取文件内容
|
||||
std::vector<BYTE> GetFileContentByte(std::string path); // 获取文件内容
|
||||
|
||||
bool InitFlag = false;
|
||||
};
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
#include "Game.h"
|
||||
#include "squirrel/SquirrelEx.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Component/Text.h"
|
||||
#include "EngineFrame/Actor/Debug_Actor.h"
|
||||
|
||||
Game::Game()
|
||||
{
|
||||
}
|
||||
|
||||
Game::~Game()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Game::Init(std::function<void()> CallBack)
|
||||
{
|
||||
// 计算帧时间
|
||||
m_frameTime = 1000 / m_fps;
|
||||
|
||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_JoystickEventState(SDL_ENABLE);
|
||||
SDL_JoystickOpen(0);
|
||||
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not initialize! Error: %s\n", SDL_GetError());
|
||||
m_isRunning = false;
|
||||
}
|
||||
m_window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Screen_W, Screen_H, SDL_WINDOW_SHOWN);
|
||||
if (m_window == nullptr)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Window! Error: %s\n", SDL_GetError());
|
||||
m_isRunning = false;
|
||||
}
|
||||
|
||||
// 创建渲染器
|
||||
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (m_renderer == nullptr)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Renderer! Error: %s\n", SDL_GetError());
|
||||
m_isRunning = false;
|
||||
}
|
||||
// 启用渲染器的混合功能(必须,否则纹理混合模式无效)
|
||||
SDL_SetRenderDrawBlendMode(m_renderer, SDL_BLENDMODE_BLEND);
|
||||
IMG_Init(IMG_INIT_PNG);
|
||||
|
||||
// 初始化SDL_mixer,支持OGG格式
|
||||
// 44100: 采样率, MIX_DEFAULT_FORMAT: 音频格式, 2: 声道数(立体声), 4096: 缓冲区大小
|
||||
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL_mixer初始化失败! Mix_Error: %s\n", Mix_GetError());
|
||||
m_isRunning = false;
|
||||
}
|
||||
|
||||
// 初始化 TTF
|
||||
if (TTF_Init() == -1)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "TTF 初始化失败!TTF_Error: %s\n", TTF_GetError());
|
||||
m_isRunning = false;
|
||||
}
|
||||
// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
|
||||
|
||||
m_DebugInfoActor = new Debug_Actor();
|
||||
CallBack();
|
||||
}
|
||||
|
||||
void Game::Run()
|
||||
{
|
||||
while (m_isRunning)
|
||||
{
|
||||
// 帧开始时间
|
||||
u32 frameStart = SDL_GetTicks();
|
||||
SDL_Event m_event;
|
||||
HandleEvents(&m_event);
|
||||
Update(m_deltaTime);
|
||||
Render(m_deltaTime);
|
||||
|
||||
// -------------------------- 新增:帧率统计与输出 --------------------------
|
||||
m_frameCount++; // 每帧递增计数器
|
||||
u32 currentTime = SDL_GetTicks();
|
||||
// 判断是否已过去 1 秒(1000 毫秒)
|
||||
if (currentTime - m_lastFpsPrintTime >= 1000)
|
||||
{
|
||||
// 计算帧率:总帧数 / 1秒 = 帧率(如 60 帧 → 60FPS)
|
||||
u32 fps = m_frameCount;
|
||||
// 输出帧率(用 SDL_Log 或 printf 均可,SDL_Log 更适配 SDL 日志系统)
|
||||
// SDL_Log("当前帧率:%d FPS | DeltaTime:%.4f 秒", fps, m_deltaTime);
|
||||
if (m_DebugInfoActor)
|
||||
m_DebugInfoActor->FPS = fps;
|
||||
|
||||
// 重置统计:更新“上一次输出时间”,重置“帧数计数器”
|
||||
m_lastFpsPrintTime = currentTime;
|
||||
m_frameCount = 0;
|
||||
}
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// 原有逻辑:控制帧间隔(保留,无需修改)
|
||||
u32 diff = SDL_GetTicks() - frameStart;
|
||||
if (diff < m_frameTime)
|
||||
{
|
||||
SDL_Delay(m_frameTime - diff);
|
||||
m_deltaTime = m_frameTime / 1000.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_deltaTime = diff / 1000.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Game::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
while (SDL_PollEvent(e))
|
||||
{
|
||||
if (e->type == SDL_QUIT)
|
||||
{
|
||||
m_isRunning = false;
|
||||
SDL_Log("Game Exit1");
|
||||
}
|
||||
else if (e->type == SDL_JOYBUTTONDOWN)
|
||||
{
|
||||
if (e->jbutton.button == JOY_PLUS)
|
||||
{
|
||||
m_isRunning = false;
|
||||
SDL_Log("Game Exit2");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_scene != nullptr)
|
||||
m_scene->HandleEvents(e);
|
||||
if (m_uiScene != nullptr)
|
||||
m_uiScene->HandleEvents(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::Update(float deltaTime)
|
||||
{
|
||||
if (m_scene != nullptr)
|
||||
m_scene->Update(deltaTime);
|
||||
if (m_uiScene != nullptr)
|
||||
m_uiScene->Update(deltaTime);
|
||||
|
||||
// 调试信息
|
||||
if (m_DebugInfoActor != nullptr)
|
||||
m_DebugInfoActor->Update(deltaTime);
|
||||
}
|
||||
|
||||
void Game::Render(float deltaTime)
|
||||
{
|
||||
SDL_RenderClear(m_renderer);
|
||||
if (m_scene != nullptr)
|
||||
m_scene->Render(deltaTime);
|
||||
if (m_uiScene != nullptr)
|
||||
m_uiScene->Render(deltaTime);
|
||||
if (m_DebugInfoActor != nullptr)
|
||||
m_DebugInfoActor->Render(deltaTime);
|
||||
SDL_RenderPresent(m_renderer);
|
||||
}
|
||||
|
||||
void Game::Clear()
|
||||
{
|
||||
if (m_scene != nullptr)
|
||||
{
|
||||
m_scene->Exit();
|
||||
}
|
||||
m_scene = nullptr;
|
||||
if (m_uiScene != nullptr)
|
||||
{
|
||||
m_uiScene->Exit();
|
||||
}
|
||||
m_uiScene = nullptr;
|
||||
m_DebugInfoActor = nullptr;
|
||||
IMG_Quit();
|
||||
SDL_DestroyRenderer(m_renderer);
|
||||
SDL_DestroyWindow(m_window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void Game::ChangeScene(RefPtr<Scene> scene)
|
||||
{
|
||||
if (m_scene != nullptr)
|
||||
{
|
||||
m_scene->Exit();
|
||||
}
|
||||
m_scene = scene;
|
||||
m_scene->Enter();
|
||||
}
|
||||
|
||||
void Game::ChangeUIScene(RefPtr<Scene> scene)
|
||||
{
|
||||
if (m_uiScene != nullptr)
|
||||
{
|
||||
m_uiScene->Exit();
|
||||
}
|
||||
m_uiScene = scene;
|
||||
m_uiScene->Enter();
|
||||
}
|
||||
|
||||
SDL_Renderer *Game::GetRenderer()
|
||||
{
|
||||
return m_renderer;
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
#include "Tool/RefPtr.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
#include <SDL_mixer.h>
|
||||
#include <SDL_ttf.h>
|
||||
#include <switch.h>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
// some switch buttons
|
||||
#define JOY_A 0
|
||||
#define JOY_B 1
|
||||
#define JOY_X 2
|
||||
#define JOY_Y 3
|
||||
#define JOY_PLUS 10
|
||||
#define JOY_MINUS 11
|
||||
#define JOY_LEFT 12
|
||||
#define JOY_UP 13
|
||||
#define JOY_RIGHT 14
|
||||
#define JOY_DOWN 15
|
||||
|
||||
class Debug_Actor;
|
||||
|
||||
class Game
|
||||
{
|
||||
|
||||
public:
|
||||
// 删除拷贝构造和赋值运算符,确保无法复制
|
||||
Game(const Game &) = delete;
|
||||
Game &operator=(const Game &) = delete;
|
||||
|
||||
// 移动构造和赋值也删除,避免意外转移
|
||||
Game(Game &&) = delete;
|
||||
Game &operator=(Game &&) = delete;
|
||||
|
||||
// 全局访问点
|
||||
static Game &GetInstance()
|
||||
{
|
||||
static Game instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Init(std::function<void()> CallBack);
|
||||
void Run();
|
||||
void HandleEvents(SDL_Event *e);
|
||||
void Update(float deltaTime);
|
||||
void Render(float deltaTime);
|
||||
void Clear();
|
||||
|
||||
// 切换场景
|
||||
void ChangeScene(RefPtr<Scene> scene);
|
||||
// 设定UI层场景对象
|
||||
void ChangeUIScene(RefPtr<Scene> scene);
|
||||
|
||||
SDL_Renderer *GetRenderer();
|
||||
|
||||
private:
|
||||
// 构造函数和析构函数设为私有,防止外部创建和销毁
|
||||
Game();
|
||||
~Game();
|
||||
|
||||
// 游戏是否运行
|
||||
bool m_isRunning = true;
|
||||
// 窗口
|
||||
SDL_Window *m_window;
|
||||
// 渲染器
|
||||
SDL_Renderer *m_renderer;
|
||||
|
||||
// 游戏层场景
|
||||
RefPtr<Scene> m_scene;
|
||||
// UI层场景
|
||||
RefPtr<Scene> m_uiScene;
|
||||
|
||||
// 屏幕宽高
|
||||
int Screen_W = 1280;
|
||||
int Screen_H = 720;
|
||||
|
||||
// 帧数
|
||||
int m_fps = 10000;
|
||||
u32 m_frameTime;
|
||||
float m_deltaTime;
|
||||
// 新增:帧率统计变量
|
||||
u32 m_frameCount; // 每秒内的帧数计数器
|
||||
u32 m_lastFpsPrintTime; // 上一次输出帧率的时间(毫秒,基于 SDL_GetTicks())
|
||||
|
||||
// 调试信息Actor
|
||||
RefPtr<Debug_Actor> m_DebugInfoActor;
|
||||
};
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#include "Actor.h"
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
|
||||
Actor::Actor()
|
||||
{
|
||||
}
|
||||
|
||||
Actor::~Actor()
|
||||
{
|
||||
}
|
||||
|
||||
void Actor::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void Actor::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Actor::Update(float deltaTime)
|
||||
{
|
||||
Actor_base::Update(deltaTime);
|
||||
RefPtr<Component> child = m_Components.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
child->Update(deltaTime);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::Render(float deltaTime)
|
||||
{
|
||||
Actor_base::Render(deltaTime);
|
||||
RefPtr<Component> child = m_Components.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
child->Render(deltaTime);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Actor::AddComponent(RefPtr<Component> Component)
|
||||
{
|
||||
m_Components.PushBack(Component);
|
||||
Component->Parent = this;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "EngineFrame/Actor/Actor_base.h"
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
class Scene;
|
||||
/**
|
||||
* @brief Actor类,继承自Actor_base类
|
||||
*
|
||||
* Actor类是一个基础的游戏对象类,可以添加到场景中
|
||||
*/
|
||||
class Actor : public Actor_base, protected IntrusiveListValue<RefPtr<Actor>>
|
||||
{
|
||||
public:
|
||||
Actor();
|
||||
~Actor() override;
|
||||
|
||||
public:
|
||||
void Init() override;
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render(float deltaTime) override;
|
||||
void Clear() override;
|
||||
|
||||
using IntrusiveListValue<RefPtr<Actor>>::GetNext;
|
||||
using IntrusiveListValue<RefPtr<Actor>>::GetPrev;
|
||||
|
||||
public:
|
||||
void AddComponent(RefPtr<Component> Component);
|
||||
|
||||
public:
|
||||
Scene *Parent; // 指向父场景的指针,表示该Actor所属的场景
|
||||
|
||||
private:
|
||||
IntrusiveList<RefPtr<Component>> m_Components;
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#include "Actor_base.h"
|
||||
|
||||
void Actor_base::Init()
|
||||
{
|
||||
}
|
||||
void Actor_base::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Actor_base::Update(float deltaTime)
|
||||
{
|
||||
if (cb_update_)
|
||||
{
|
||||
cb_update_(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Actor_base::Render(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Actor_base::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Actor_base::SetCallbackOnUpdate(const UpdateCallback &cb)
|
||||
{
|
||||
cb_update_ = cb;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include "Tool/RefPtr.h"
|
||||
#include "Tool/RefObject.h"
|
||||
#include <functional>
|
||||
#include <SDL.h>
|
||||
class Actor_base : public RefObject
|
||||
{
|
||||
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 角色更新回调函数
|
||||
typedef std::function<void(float deltaTime)> UpdateCallback;
|
||||
|
||||
public:
|
||||
Actor_base(/* args */) = default;
|
||||
virtual ~Actor_base() = default;
|
||||
|
||||
virtual void Init();
|
||||
virtual void HandleEvents(SDL_Event *e);
|
||||
virtual void Update(float deltaTime);
|
||||
virtual void Render(float deltaTime);
|
||||
virtual void Clear();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置更新时的回调函数
|
||||
void SetCallbackOnUpdate(const UpdateCallback &cb);
|
||||
|
||||
private:
|
||||
/* data */
|
||||
UpdateCallback cb_update_; // 更新时的回调函数
|
||||
};
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
#include "Debug_Actor.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include <string>
|
||||
|
||||
Debug_Actor::Debug_Actor()
|
||||
{
|
||||
m_debugFont = TTF_OpenFont("Fonts/GasinamuNew.ttf", 16);
|
||||
if (m_debugFont == nullptr)
|
||||
{
|
||||
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load debug font: %s", TTF_GetError());
|
||||
}
|
||||
|
||||
FPS_Text = new Text("Current FPS:", m_debugFont, SDL_Color{255, 255, 255, 255});
|
||||
DT_Text = new Text("DeltaTime :", m_debugFont, SDL_Color{255, 255, 255, 255});
|
||||
if (FPS_Text != nullptr)
|
||||
{
|
||||
SDL_Point Pos{26, 26};
|
||||
FPS_Text->SetPos(Pos);
|
||||
this->AddComponent(FPS_Text);
|
||||
}
|
||||
if (DT_Text != nullptr)
|
||||
{
|
||||
SDL_Point Pos{26, 46};
|
||||
DT_Text->SetPos(Pos);
|
||||
this->AddComponent(DT_Text);
|
||||
}
|
||||
}
|
||||
|
||||
Debug_Actor::~Debug_Actor()
|
||||
{
|
||||
|
||||
if (m_debugFont != nullptr)
|
||||
{
|
||||
TTF_CloseFont(m_debugFont);
|
||||
m_debugFont = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Debug_Actor::Update(float deltaTime)
|
||||
{
|
||||
Actor::Update(deltaTime);
|
||||
|
||||
if (FPS_Text != nullptr)
|
||||
{
|
||||
std::string fpsText = "Current FPS: " + std::to_string(FPS);
|
||||
FPS_Text->SetText(fpsText);
|
||||
std::string dtText = "DeltaTime: " + std::to_string((int)(deltaTime * 1000));
|
||||
DT_Text->SetText(dtText);
|
||||
}
|
||||
}
|
||||
|
||||
void Debug_Actor::Render(float deltaTime)
|
||||
{
|
||||
if (FPS_Text != nullptr)
|
||||
{
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
if (renderer != nullptr)
|
||||
{
|
||||
|
||||
SDL_Point textPos = FPS_Text->Pos;
|
||||
SDL_Point textSize = FPS_Text->Size;
|
||||
|
||||
int bgX = textPos.x - padding;
|
||||
int bgY = textPos.y - padding;
|
||||
int bgWidth = textSize.x + padding * 2;
|
||||
int bgHeight = textSize.y + padding * 2 * 4;
|
||||
|
||||
DrawRoundedRect(renderer, bgX, bgY, bgWidth, bgHeight, cornerRadius, bgColor);
|
||||
}
|
||||
}
|
||||
|
||||
Actor::Render(deltaTime);
|
||||
}
|
||||
|
||||
void Debug_Actor::DrawRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h, int radius, SDL_Color color)
|
||||
{
|
||||
if (renderer == nullptr)
|
||||
return;
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
|
||||
|
||||
SDL_RenderDrawLine(renderer, x + radius, y, x + w - radius, y);
|
||||
SDL_RenderDrawLine(renderer, x + radius, y + h, x + w - radius, y + h);
|
||||
SDL_RenderDrawLine(renderer, x, y + radius, x, y + h - radius);
|
||||
SDL_RenderDrawLine(renderer, x + w, y + radius, x + w, y + h - radius);
|
||||
|
||||
const int segments = 16;
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
|
||||
float t1 = static_cast<float>(i) / segments;
|
||||
float t2 = static_cast<float>(i + 1) / segments;
|
||||
|
||||
float angle1 = M_PI * (1.0f - t1);
|
||||
float angle2 = M_PI * (1.0f - t2);
|
||||
SDL_RenderDrawLineF(
|
||||
renderer,
|
||||
x + radius + cos(angle1) * radius, y + radius + sin(angle1) * radius,
|
||||
x + radius + cos(angle2) * radius, y + radius + sin(angle2) * radius);
|
||||
|
||||
angle1 = 2 * M_PI - t1 * M_PI_2;
|
||||
angle2 = 2 * M_PI - t2 * M_PI_2;
|
||||
SDL_RenderDrawLineF(
|
||||
renderer,
|
||||
x + w - radius + cos(angle1) * radius, y + radius + sin(angle1) * radius,
|
||||
x + w - radius + cos(angle2) * radius, y + radius + sin(angle2) * radius);
|
||||
|
||||
angle1 = t1 * M_PI_2;
|
||||
angle2 = t2 * M_PI_2;
|
||||
SDL_RenderDrawLineF(
|
||||
renderer,
|
||||
x + w - radius + cos(angle1) * radius, y + h - radius + sin(angle1) * radius,
|
||||
x + w - radius + cos(angle2) * radius, y + h - radius + sin(angle2) * radius);
|
||||
|
||||
angle1 = M_PI_2 + t1 * M_PI_2;
|
||||
angle2 = M_PI_2 + t2 * M_PI_2;
|
||||
SDL_RenderDrawLineF(
|
||||
renderer,
|
||||
x + radius + cos(angle1) * radius, y + h - radius + sin(angle1) * radius,
|
||||
x + radius + cos(angle2) * radius, y + h - radius + sin(angle2) * radius);
|
||||
}
|
||||
|
||||
for (int dy = 0; dy < h; dy++)
|
||||
{
|
||||
int leftIndent = 0;
|
||||
int rightIndent = 0;
|
||||
|
||||
if (dy < radius)
|
||||
{
|
||||
float ratio = 1.0f - static_cast<float>(dy) / radius;
|
||||
leftIndent = rightIndent = static_cast<int>(radius * (1.0f - sqrt(1.0f - ratio * ratio)));
|
||||
}
|
||||
|
||||
else if (dy > h - radius)
|
||||
{
|
||||
float ratio = static_cast<float>(dy - (h - radius)) / radius;
|
||||
leftIndent = rightIndent = static_cast<int>(radius * (1.0f - sqrt(1.0f - ratio * ratio)));
|
||||
}
|
||||
|
||||
SDL_RenderDrawLine(
|
||||
renderer,
|
||||
x + leftIndent, y + dy,
|
||||
x + w - rightIndent, y + dy);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Component/Text.h"
|
||||
#include <SDL_ttf.h>
|
||||
#include <cstdint>
|
||||
|
||||
class Debug_Actor : public Actor
|
||||
{
|
||||
private:
|
||||
TTF_Font *m_debugFont;
|
||||
RefPtr<Text> FPS_Text;
|
||||
RefPtr<Text> DT_Text;
|
||||
|
||||
public:
|
||||
Debug_Actor();
|
||||
~Debug_Actor() override;
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Render(float deltaTime) override;
|
||||
|
||||
uint32_t FPS = 0;
|
||||
|
||||
SDL_Color bgColor = {0, 0, 0, 90};
|
||||
|
||||
int cornerRadius = 4;
|
||||
int padding = 12;
|
||||
double M_PI = 3.14159265358979323846;
|
||||
double M_PI_2 = 1.57079632679489661923;
|
||||
|
||||
private:
|
||||
void DrawRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h, int radius, SDL_Color color);
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#include "Component.h"
|
||||
|
||||
Component::Component()
|
||||
{
|
||||
}
|
||||
|
||||
Component::~Component()
|
||||
{
|
||||
}
|
||||
|
||||
void Component::Init()
|
||||
{
|
||||
}
|
||||
void Component::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Component::Update(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Component::Render(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Component::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Component::SetName(std::string name)
|
||||
{
|
||||
m_Name = name;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
#include "Tool/RefPtr.h"
|
||||
#include "Tool/RefObject.h"
|
||||
#include "Tool/TagGed.h"
|
||||
|
||||
#include <SDL.h>
|
||||
class Actor;
|
||||
class Component : public RefObject, public TagGed, protected IntrusiveListValue<RefPtr<Component>>
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
std::string m_Name;
|
||||
public:
|
||||
Component(/* args */);
|
||||
~Component();
|
||||
|
||||
virtual void Init();
|
||||
virtual void HandleEvents(SDL_Event *e);
|
||||
virtual void Update(float deltaTime);
|
||||
virtual void Render(float deltaTime);
|
||||
virtual void Clear();
|
||||
|
||||
using IntrusiveListValue<RefPtr<Component>>::GetNext;
|
||||
using IntrusiveListValue<RefPtr<Component>>::GetPrev;
|
||||
|
||||
void SetName(std::string name);
|
||||
|
||||
public:
|
||||
Actor *Parent; // 指向父对象的指针,用于访问父对象
|
||||
};
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
#include "Sprite.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "Text.h"
|
||||
Sprite::Sprite()
|
||||
{
|
||||
}
|
||||
|
||||
Sprite::Sprite(std::string imgPath, int Index)
|
||||
{
|
||||
Init(imgPath, Index);
|
||||
}
|
||||
|
||||
Sprite::~Sprite()
|
||||
{
|
||||
SDL_DestroyTexture(m_texture);
|
||||
}
|
||||
|
||||
void Sprite::Init(std::string imgPath, int Index)
|
||||
{
|
||||
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(imgPath);
|
||||
Asset_ImagePack::ImgInfo &Buf = Info->lp_lplist[Index];
|
||||
|
||||
m_texture = SDL_CreateTexture(
|
||||
Game::GetInstance().GetRenderer(),
|
||||
SDL_PIXELFORMAT_ARGB8888, // 匹配RGBA数据格式
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
Buf.Width, Buf.Height);
|
||||
if (!m_texture)
|
||||
{
|
||||
SDL_Log("纹理创建失败: %s", SDL_GetError());
|
||||
}
|
||||
int pitch = Buf.Width * 4;
|
||||
SDL_UpdateTexture(m_texture, NULL, Buf.PNGdata, pitch);
|
||||
|
||||
if (Info != NULL)
|
||||
{
|
||||
// SDL_Log("第%d张图片的宽度为%d,高度为%d\n", Index, Buf.Width, Buf.Height);
|
||||
}
|
||||
TextureSize.x = Buf.Width;
|
||||
TextureSize.y = Buf.Height;
|
||||
Size.x = Buf.Width;
|
||||
Size.y = Buf.Height;
|
||||
}
|
||||
|
||||
SDL_Texture *Sprite::GetTexture()
|
||||
{
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
void Sprite::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Sprite::Update(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Sprite::Render(float deltaTime)
|
||||
{
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
if (!m_texture)
|
||||
return;
|
||||
SDL_Rect dstrect = {Pos.x, Pos.y, Size.x, Size.y};
|
||||
|
||||
if (Angle != 0 || flip != SDL_FLIP_NONE)
|
||||
{
|
||||
SDL_RenderCopyEx(renderer, m_texture, NULL, &dstrect, Angle, &Anchor, flip);
|
||||
}
|
||||
else
|
||||
SDL_RenderCopy(renderer, m_texture, NULL, &dstrect);
|
||||
}
|
||||
|
||||
void Sprite::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Sprite::SetPos(SDL_Point pos)
|
||||
{
|
||||
Pos = pos;
|
||||
}
|
||||
|
||||
void Sprite::SetBlendMode(SDL_BlendMode blendMode)
|
||||
{
|
||||
SDL_SetTextureBlendMode(m_texture, blendMode);
|
||||
}
|
||||
|
||||
void Sprite::SetAngle(float angle)
|
||||
{
|
||||
Angle = angle;
|
||||
}
|
||||
|
||||
void Sprite::SetAnchor(SDL_FPoint anchor)
|
||||
{
|
||||
Anchor.x = Size.x * anchor.x;
|
||||
Anchor.y = Size.y * anchor.y;
|
||||
}
|
||||
|
||||
SDL_Point Sprite::GetPos()
|
||||
{
|
||||
return Pos;
|
||||
}
|
||||
|
||||
|
||||
SDL_BlendMode Sprite::GetBlendMode()
|
||||
{
|
||||
SDL_BlendMode blendMode;
|
||||
SDL_GetTextureBlendMode(m_texture, &blendMode);
|
||||
return blendMode;
|
||||
}
|
||||
|
||||
float Sprite::GetAngle()
|
||||
{
|
||||
return Angle;
|
||||
}
|
||||
|
||||
SDL_FPoint Sprite::GetAnchor()
|
||||
{
|
||||
SDL_FPoint P;
|
||||
P.x = Anchor.x / Size.x;
|
||||
P.y = Anchor.y / Size.y;
|
||||
return P;
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "EngineCore/Asset_ImagePack.h"
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
|
||||
class Game;
|
||||
/**
|
||||
* @brief Sprite类,继承自Component类,用于表示游戏中的精灵组件
|
||||
*/
|
||||
class Sprite : public Component
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
SDL_Texture *m_texture = nullptr; // 纹理指针,用于存储精灵的纹理资源
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Sprite类的默认构造函数
|
||||
*/
|
||||
Sprite(/* args */);
|
||||
/**
|
||||
* @brief Sprite类的带参数构造函数
|
||||
* @param imgPath 纹理图片路径
|
||||
* @param Index 索引值
|
||||
*/
|
||||
Sprite(std::string imgPath, int Index);
|
||||
/**
|
||||
* @brief Sprite类的析构函数
|
||||
*/
|
||||
~Sprite();
|
||||
|
||||
// 显式引入基类的Init方法,避免隐藏
|
||||
using Component::Init;
|
||||
/**
|
||||
* @brief 初始化Sprite组件
|
||||
* @param imgPath 纹理图片路径
|
||||
* @param Index 索引值
|
||||
*/
|
||||
void Init(std::string imgPath, int Index);
|
||||
/**
|
||||
* @brief 处理事件
|
||||
* @param e SDL事件指针
|
||||
*/
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
/**
|
||||
* @brief 更新组件状态
|
||||
* @param deltaTime 时间增量
|
||||
*/
|
||||
void Update(float deltaTime) override;
|
||||
/**
|
||||
* @brief 渲染组件
|
||||
* @param deltaTime 时间增量
|
||||
*/
|
||||
void Render(float deltaTime) override;
|
||||
/**
|
||||
* @brief 清理组件资源
|
||||
*/
|
||||
void Clear() override;
|
||||
|
||||
/**
|
||||
* @brief 获取纹理
|
||||
* @return SDL_Texture* 纹理指针
|
||||
*/
|
||||
SDL_Texture *GetTexture();
|
||||
|
||||
public:
|
||||
// 组件标签
|
||||
Tag m_tag = Tag::RENDER | Tag::UPDATE; // 标记该组件需要渲染和更新
|
||||
|
||||
SDL_Point Pos = {0, 0}; // 位置坐标
|
||||
SDL_Point TextureSize = {0, 0}; // 纹理大小
|
||||
SDL_Point Size = {0, 0}; // 大小
|
||||
SDL_Point Anchor = {0, 0}; // 中心点
|
||||
float Angle = 0.0f; // 旋转角度
|
||||
SDL_RendererFlip flip = SDL_FLIP_NONE; // 翻转
|
||||
|
||||
public:
|
||||
// 设置坐标
|
||||
void SetPos(SDL_Point pos);
|
||||
// 设置混合模式
|
||||
void SetBlendMode(SDL_BlendMode blendMode);
|
||||
// 设置旋转角度
|
||||
void SetAngle(float angle);
|
||||
//设置中心点
|
||||
void SetAnchor(SDL_FPoint anchor);
|
||||
|
||||
// 获取坐标
|
||||
SDL_Point GetPos();
|
||||
// 获取混合模式
|
||||
SDL_BlendMode GetBlendMode();
|
||||
// 获取旋转角度
|
||||
float GetAngle();
|
||||
// 获取中心点
|
||||
SDL_FPoint GetAnchor();
|
||||
};
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
#include "EngineFrame/Component/Text.h"
|
||||
#include "Text.h"
|
||||
#include "EngineCore/Game.h"
|
||||
Text::Text()
|
||||
{
|
||||
}
|
||||
|
||||
Text::Text(std::string Str, TTF_Font *font, SDL_Color color)
|
||||
{
|
||||
m_text = Str;
|
||||
m_font = font;
|
||||
m_text_color = color;
|
||||
Init(Str, font, color);
|
||||
}
|
||||
|
||||
Text::Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
|
||||
{
|
||||
m_text = Str;
|
||||
m_font = font;
|
||||
m_text_color = textColor;
|
||||
m_stroke_color = strokeColor;
|
||||
m_stroke_size = strokeSize;
|
||||
Init(Str, font, textColor, strokeColor, strokeSize);
|
||||
}
|
||||
|
||||
Text::~Text()
|
||||
{
|
||||
}
|
||||
|
||||
void Text::Init(std::string Str, TTF_Font *font, SDL_Color color)
|
||||
{
|
||||
// TTF_SetFontOutline(font, 1);
|
||||
// 先渲染为表面
|
||||
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), color);
|
||||
if (!textSurface)
|
||||
{
|
||||
SDL_LogError(0, "文字渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||||
}
|
||||
// 再将表面转换为纹理
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
m_texture = SDL_CreateTextureFromSurface(renderer, textSurface);
|
||||
if (!m_texture)
|
||||
{
|
||||
SDL_LogError(0, "表面转换为纹理失败!SDL_Error:%s", SDL_GetError());
|
||||
}
|
||||
// 设置纹理过滤模式为最近邻,避免缩放模糊
|
||||
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeNearest);
|
||||
Size.x = textSurface->w;
|
||||
Size.y = textSurface->h;
|
||||
TextureSize.x = textSurface->w;
|
||||
TextureSize.y = textSurface->h;
|
||||
|
||||
// 释放表面
|
||||
SDL_FreeSurface(textSurface);
|
||||
}
|
||||
|
||||
void Text::Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
|
||||
{
|
||||
// 先保存原始字体的轮廓设置
|
||||
int originalOutline = TTF_GetFontOutline(font);
|
||||
|
||||
// 设置字体轮廓大小(描边宽度)
|
||||
TTF_SetFontOutline(font, strokeSize);
|
||||
|
||||
// 渲染描边(使用描边颜色)
|
||||
SDL_Surface *strokeSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), strokeColor);
|
||||
if (!strokeSurface)
|
||||
{
|
||||
SDL_LogError(0, "描边渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||||
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
|
||||
return;
|
||||
}
|
||||
|
||||
// 恢复字体轮廓设置,用于渲染文字本身
|
||||
TTF_SetFontOutline(font, 0);
|
||||
|
||||
// 渲染文字本身(使用文字颜色)
|
||||
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), textColor);
|
||||
if (!textSurface)
|
||||
{
|
||||
SDL_LogError(0, "文字渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||||
SDL_FreeSurface(strokeSurface);
|
||||
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建一个合并描边和文字的表面
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
|
||||
// 计算最终纹理大小(描边会增加额外尺寸)
|
||||
int finalWidth = strokeSurface->w;
|
||||
int finalHeight = strokeSurface->h;
|
||||
|
||||
// 创建一个临时表面用于合并描边和文字
|
||||
SDL_Surface *finalSurface = SDL_CreateRGBSurfaceWithFormat(
|
||||
0, finalWidth, finalHeight, 32, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!finalSurface)
|
||||
{
|
||||
SDL_LogError(0, "创建最终表面失败!SDL_Error:%s", SDL_GetError());
|
||||
SDL_FreeSurface(textSurface);
|
||||
SDL_FreeSurface(strokeSurface);
|
||||
TTF_SetFontOutline(font, originalOutline);
|
||||
return;
|
||||
}
|
||||
|
||||
// 将描边绘制到最终表面
|
||||
SDL_Rect strokeRect = {0, 0, strokeSurface->w, strokeSurface->h};
|
||||
SDL_BlitSurface(strokeSurface, nullptr, finalSurface, &strokeRect);
|
||||
|
||||
// 计算文字在描边中间的位置
|
||||
SDL_Rect textRect = {
|
||||
strokeSize, // X偏移(描边宽度)
|
||||
strokeSize, // Y偏移(描边宽度)
|
||||
textSurface->w,
|
||||
textSurface->h};
|
||||
SDL_BlitSurface(textSurface, nullptr, finalSurface, &textRect);
|
||||
|
||||
// 将合并后的表面转换为纹理
|
||||
m_texture = SDL_CreateTextureFromSurface(renderer, finalSurface);
|
||||
if (!m_texture)
|
||||
{
|
||||
SDL_LogError(0, "表面转换为纹理失败!SDL_Error:%s", SDL_GetError());
|
||||
}
|
||||
|
||||
// 设置尺寸信息
|
||||
Size.x = finalSurface->w;
|
||||
Size.y = finalSurface->h;
|
||||
TextureSize.x = finalSurface->w;
|
||||
TextureSize.y = finalSurface->h;
|
||||
|
||||
// 释放所有临时表面
|
||||
SDL_FreeSurface(textSurface);
|
||||
SDL_FreeSurface(strokeSurface);
|
||||
SDL_FreeSurface(finalSurface);
|
||||
|
||||
// 恢复字体原始轮廓设置
|
||||
TTF_SetFontOutline(font, originalOutline);
|
||||
}
|
||||
|
||||
void Text::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Text::Update(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Text::Render(float deltaTime)
|
||||
{
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
if (!renderer || !m_texture)
|
||||
return;
|
||||
SDL_Rect dstrect = {Pos.x, Pos.y, Size.x, Size.y};
|
||||
|
||||
SDL_RenderCopy(renderer, m_texture, NULL, &dstrect);
|
||||
}
|
||||
|
||||
void Text::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Text::SetPos(SDL_Point pos)
|
||||
{
|
||||
Pos = pos;
|
||||
}
|
||||
|
||||
SDL_Point Text::GetPos()
|
||||
{
|
||||
return Pos;
|
||||
}
|
||||
|
||||
void Text::SetText(std::string Str)
|
||||
{
|
||||
if (Str == m_text)
|
||||
return;
|
||||
if (!m_font)
|
||||
{
|
||||
SDL_LogError(0, "SetText失败:字体指针为空!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有原纹理先删除原纹理
|
||||
if (m_texture)
|
||||
{
|
||||
SDL_DestroyTexture(m_texture);
|
||||
m_texture = nullptr; // 置空指针
|
||||
}
|
||||
m_text = Str;
|
||||
// 根据是否有描边选择对应的Init方法
|
||||
if (m_stroke_size > 0)
|
||||
{
|
||||
Init(Str, m_font, m_text_color, m_stroke_color, m_stroke_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Init(Str, m_font, m_text_color);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Text::GetText()
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
class Game;
|
||||
|
||||
class Text : public Component
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
SDL_Texture *m_texture = nullptr;
|
||||
|
||||
public:
|
||||
Text(/* args */);
|
||||
Text(std::string Str, TTF_Font *font, SDL_Color color);
|
||||
Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
|
||||
~Text();
|
||||
|
||||
// 显式引入基类的Init方法,避免隐藏
|
||||
using Component::Init;
|
||||
void Init(std::string Str, TTF_Font *font, SDL_Color color);
|
||||
void Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render(float deltaTime) override;
|
||||
void Clear() override;
|
||||
|
||||
SDL_Texture *GetTexture();
|
||||
|
||||
public:
|
||||
// 组件标签
|
||||
Tag m_tag = Tag::RENDER | Tag::UPDATE; // 标记该组件需要渲染和更新
|
||||
|
||||
std::string m_text;
|
||||
TTF_Font *m_font;
|
||||
SDL_Color m_text_color;
|
||||
SDL_Color m_stroke_color;
|
||||
int m_stroke_size = 0;
|
||||
|
||||
SDL_Point Pos = {0, 0}; // 位置坐标
|
||||
SDL_Point TextureSize = {0, 0}; // 纹理大小
|
||||
SDL_Point Size = {0, 0}; // 大小
|
||||
SDL_Point Anchor = {0, 0}; // 中心点
|
||||
float Angle = 0.0f; // 旋转角度
|
||||
SDL_RendererFlip flip = SDL_FLIP_NONE; // 翻转
|
||||
|
||||
public:
|
||||
// 设置坐标
|
||||
void SetPos(SDL_Point pos);
|
||||
// 设置文本
|
||||
void SetText(std::string Str);
|
||||
|
||||
// 获取坐标
|
||||
SDL_Point GetPos();
|
||||
// 获取文本
|
||||
std::string GetText();
|
||||
};
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#include "EngineFrame/Scene/Scene.h"
|
||||
#include "Scene.h"
|
||||
|
||||
void Scene::Enter()
|
||||
{
|
||||
}
|
||||
|
||||
void Scene::Exit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Scene::AddChild(RefPtr<Actor> actor)
|
||||
{
|
||||
m_Actors.PushBack(actor);
|
||||
actor->Parent = this;
|
||||
}
|
||||
|
||||
void Scene::Update(float deltaTime)
|
||||
{
|
||||
RefPtr<Actor> child = m_Actors.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
child->Update(deltaTime);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::Render(float deltaTime)
|
||||
{
|
||||
RefPtr<Actor> child = m_Actors.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
child->Render(deltaTime);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include "EngineFrame/Scene/Scene_Base.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
#include "Tool/RefPtr.h"
|
||||
#include <SDL.h>
|
||||
#include <switch.h>
|
||||
#include <memory>
|
||||
class Scene : public Scene_Base, public RefObject
|
||||
{
|
||||
public:
|
||||
void Enter() override;
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render(float deltaTime) override;
|
||||
void Exit() override;
|
||||
|
||||
public:
|
||||
void AddChild(RefPtr<Actor> actor);
|
||||
private:
|
||||
IntrusiveList<RefPtr<Actor>> m_Actors;
|
||||
};
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <SDL.h>
|
||||
#include <switch.h>
|
||||
class Scene_Base
|
||||
{
|
||||
public:
|
||||
Scene_Base() = default;
|
||||
virtual ~Scene_Base() = default;
|
||||
|
||||
virtual void Enter() = 0;
|
||||
virtual void HandleEvents(SDL_Event *e) = 0;
|
||||
virtual void Update(float deltaTime) = 0;
|
||||
virtual void Render(float deltaTime) = 0;
|
||||
virtual void Exit() = 0;
|
||||
};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "Tool/Allocator.h"
|
||||
|
||||
namespace memory
|
||||
{
|
||||
MemoryAllocator *current_allocator_ = nullptr;
|
||||
|
||||
MemoryAllocator *GetGlobalAllocator()
|
||||
{
|
||||
class GlobalAllocator : public MemoryAllocator
|
||||
{
|
||||
public:
|
||||
virtual void *Alloc(size_t size) override
|
||||
{
|
||||
return ::operator new(size);
|
||||
}
|
||||
|
||||
virtual void Free(void *ptr) override
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
static GlobalAllocator global_allocator;
|
||||
return &global_allocator;
|
||||
}
|
||||
|
||||
MemoryAllocator *GetAllocator()
|
||||
{
|
||||
if (!current_allocator_)
|
||||
{
|
||||
current_allocator_ = GetGlobalAllocator();
|
||||
}
|
||||
return current_allocator_;
|
||||
}
|
||||
|
||||
void SetAllocator(MemoryAllocator *allocator)
|
||||
{
|
||||
current_allocator_ = allocator;
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
#pragma once
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
namespace memory
|
||||
{
|
||||
/// \~chinese
|
||||
/// @brief 内存分配器
|
||||
class MemoryAllocator
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 申请内存
|
||||
virtual void *Alloc(size_t size) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 释放内存
|
||||
virtual void Free(void *ptr) = 0;
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取当前内存分配器
|
||||
MemoryAllocator *GetAllocator();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置当前内存分配器
|
||||
void SetAllocator(MemoryAllocator *allocator);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 使用当前内存分配器分配内存
|
||||
inline void *Alloc(size_t size)
|
||||
{
|
||||
return memory::GetAllocator()->Alloc(size);
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 使用当前内存分配器释放内存
|
||||
inline void Free(void *ptr)
|
||||
{
|
||||
memory::GetAllocator()->Free(ptr);
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 分配器
|
||||
template <typename _Ty>
|
||||
class Allocator
|
||||
{
|
||||
public:
|
||||
typedef _Ty value_type;
|
||||
typedef _Ty *pointer;
|
||||
typedef const _Ty *const_pointer;
|
||||
typedef _Ty &reference;
|
||||
typedef const _Ty &const_reference;
|
||||
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
template <class _Other>
|
||||
struct rebind
|
||||
{
|
||||
using other = Allocator<_Other>;
|
||||
};
|
||||
|
||||
Allocator() noexcept {}
|
||||
|
||||
Allocator(const Allocator &) noexcept = default;
|
||||
|
||||
template <class _Other>
|
||||
Allocator(const Allocator<_Other> &) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
inline _Ty *allocate(size_t count)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
return static_cast<_Ty *>(memory::Alloc(sizeof(_Ty) * count));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void *allocate(size_t count, const void *)
|
||||
{
|
||||
return allocate(count);
|
||||
}
|
||||
|
||||
inline void deallocate(void *ptr, size_t count)
|
||||
{
|
||||
memory::Free(ptr /*, sizeof(_Ty) * count */);
|
||||
}
|
||||
|
||||
template <typename _UTy, typename... _Args>
|
||||
inline void construct(_UTy *const ptr, _Args &&...args)
|
||||
{
|
||||
::new (const_cast<void *>(static_cast<const volatile void *>(ptr))) _Ty(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename _UTy>
|
||||
inline void destroy(_UTy *ptr)
|
||||
{
|
||||
ptr->~_UTy();
|
||||
}
|
||||
|
||||
size_t max_size() const noexcept
|
||||
{
|
||||
return std::numeric_limits<size_t>::max() / sizeof(_Ty);
|
||||
}
|
||||
|
||||
_Ty *address(_Ty &val) const noexcept
|
||||
{
|
||||
return std::addressof(val);
|
||||
}
|
||||
|
||||
const _Ty *address(const _Ty &val) const noexcept
|
||||
{
|
||||
return std::addressof(val);
|
||||
}
|
||||
};
|
||||
|
||||
// Allocator<void>
|
||||
template <>
|
||||
class Allocator<void>
|
||||
{
|
||||
public:
|
||||
using value_type = void;
|
||||
typedef void *pointer;
|
||||
typedef const void *const_pointer;
|
||||
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
template <class _Other>
|
||||
struct rebind
|
||||
{
|
||||
using other = Allocator<_Other>;
|
||||
};
|
||||
};
|
||||
|
||||
template <class _Ty, class _Other>
|
||||
bool operator==(const Allocator<_Ty> &, const Allocator<_Other> &) noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class _Ty, class _Other>
|
||||
bool operator!=(const Allocator<_Ty> &, const Allocator<_Other> &) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
|
||||
class Blob
|
||||
{
|
||||
using BYTE = unsigned char;
|
||||
|
||||
private:
|
||||
const std::vector<BYTE> &m_blob;
|
||||
size_t m_offset;
|
||||
|
||||
// 检查是否有足够的剩余字节
|
||||
void checkSize(size_t required) const
|
||||
{
|
||||
if (m_offset + required > m_blob.size())
|
||||
{
|
||||
throw std::out_of_range("Insufficient data in blob");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// 构造函数,接受一个字节向量的引用
|
||||
Blob(const std::vector<BYTE> &blob) : m_blob(blob), m_offset(0) {}
|
||||
|
||||
// 重置解析偏移量
|
||||
void reset() { m_offset = 0; }
|
||||
|
||||
// 获取当前偏移量
|
||||
size_t getOffset() const { return m_offset; }
|
||||
|
||||
// 设置偏移量
|
||||
void setOffset(size_t offset)
|
||||
{
|
||||
if (offset > m_blob.size())
|
||||
{
|
||||
throw std::out_of_range("Offset out of range");
|
||||
}
|
||||
m_offset = offset;
|
||||
}
|
||||
|
||||
// 获取剩余字节数
|
||||
size_t remaining() const { return m_blob.size() - m_offset; }
|
||||
|
||||
// 读取一个T类型的数据(适用于基本类型)
|
||||
template <typename T>
|
||||
T get()
|
||||
{
|
||||
checkSize(sizeof(T));
|
||||
|
||||
T value;
|
||||
std::copy(m_blob.begin() + m_offset,
|
||||
m_blob.begin() + m_offset + sizeof(T),
|
||||
reinterpret_cast<BYTE *>(&value));
|
||||
m_offset += sizeof(T);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// 读取int类型
|
||||
int32_t getInt() { return get<int32_t>(); }
|
||||
|
||||
// 读取无符号int类型
|
||||
uint32_t getUInt() { return get<uint32_t>(); }
|
||||
|
||||
// 读取short类型
|
||||
int16_t getShort() { return get<int16_t>(); }
|
||||
|
||||
// 读取无符号short类型
|
||||
uint16_t getUShort() { return get<uint16_t>(); }
|
||||
|
||||
// 读取float类型
|
||||
float getFloat() { return get<float>(); }
|
||||
|
||||
// 读取double类型
|
||||
double getDouble() { return get<double>(); }
|
||||
|
||||
BYTE getByte() { return get<BYTE>(); }
|
||||
|
||||
float get256()
|
||||
{
|
||||
BYTE buf = get<BYTE>();
|
||||
return static_cast<float>(buf);
|
||||
}
|
||||
|
||||
// 读取指定长度的字符串
|
||||
std::string getString(size_t length)
|
||||
{
|
||||
checkSize(length);
|
||||
|
||||
std::string str(reinterpret_cast<const char *>(m_blob.data() + m_offset), length);
|
||||
m_offset += length;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// 读取以null结尾的字符串
|
||||
std::string getNullTerminatedString()
|
||||
{
|
||||
size_t length = 0;
|
||||
size_t pos = m_offset;
|
||||
|
||||
// 查找null终止符
|
||||
while (pos < m_blob.size() && m_blob[pos] != '\0')
|
||||
{
|
||||
pos++;
|
||||
length++;
|
||||
}
|
||||
|
||||
// 确保找到了终止符
|
||||
if (pos >= m_blob.size())
|
||||
{
|
||||
throw std::runtime_error("Null-terminated string not found");
|
||||
}
|
||||
|
||||
// 读取字符串(不包含终止符)
|
||||
std::string str(reinterpret_cast<const char *>(m_blob.data() + m_offset), length);
|
||||
m_offset = pos + 1; // 跳过终止符
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// 读取指定数量的字节
|
||||
std::vector<BYTE> getBytes(size_t count)
|
||||
{
|
||||
checkSize(count);
|
||||
|
||||
std::vector<BYTE> bytes(m_blob.begin() + m_offset, m_blob.begin() + m_offset + count);
|
||||
m_offset += count;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <cstddef>
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 不可拷贝对象
|
||||
class Noncopyable
|
||||
{
|
||||
protected:
|
||||
Noncopyable() = default;
|
||||
|
||||
private:
|
||||
Noncopyable(const Noncopyable &) = delete;
|
||||
|
||||
Noncopyable &operator=(const Noncopyable &) = delete;
|
||||
};
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#include "Ifstream_NPK.h"
|
||||
|
||||
// 密钥初始化
|
||||
Ifstream_NPK::Ifstream_NPK() : Key{112, 117, 99, 104, 105, 107, 111, 110, 64, 110, 101, 111, 112, 108, 101, 32, 100, 117, 110, 103, 101, 111, 110, 32, 97, 110, 100, 32, 102, 105, 103, 104, 116, 101, 114, 32, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 0}
|
||||
{
|
||||
// 构造函数体可以为空
|
||||
}
|
||||
|
||||
// char* 转整数
|
||||
int Ifstream_NPK::CharToInt(char *Str)
|
||||
{
|
||||
return *(int *)Str;
|
||||
}
|
||||
|
||||
// char* 转Long
|
||||
long Ifstream_NPK::CharToLong(char *Str)
|
||||
{
|
||||
return *(long long *)Str;
|
||||
}
|
||||
|
||||
// 读整数
|
||||
int Ifstream_NPK::ReadInt()
|
||||
{
|
||||
char *CountBuffer = new char[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this->get(CountBuffer[i]);
|
||||
}
|
||||
int Count = CharToInt(CountBuffer);
|
||||
delete[] CountBuffer;
|
||||
return Count;
|
||||
}
|
||||
|
||||
// 读字符串
|
||||
std::string Ifstream_NPK::ReadString()
|
||||
{
|
||||
char *CharBuffer = new char[1024];
|
||||
this->get(CharBuffer, 1024, '\0');
|
||||
std::string Str = CharBuffer;
|
||||
delete[] CharBuffer;
|
||||
this->seekg(1, std::ios::cur);
|
||||
return Str;
|
||||
}
|
||||
|
||||
// 读取信息
|
||||
std::string Ifstream_NPK::ReadInfo()
|
||||
{
|
||||
char *CharBuffer = new char[256];
|
||||
char var;
|
||||
int i = 0;
|
||||
while (i < 256)
|
||||
{
|
||||
this->get(var);
|
||||
CharBuffer[i] = var ^ Key[i];
|
||||
++i;
|
||||
}
|
||||
std::string Str = CharBuffer;
|
||||
delete[] CharBuffer;
|
||||
return Str;
|
||||
}
|
||||
|
||||
// 读LONG
|
||||
int Ifstream_NPK::ReadLong()
|
||||
{
|
||||
char *CountBuffer = new char[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
this->get(CountBuffer[i]);
|
||||
}
|
||||
long Count = CharToLong(CountBuffer);
|
||||
delete[] CountBuffer;
|
||||
return Count;
|
||||
}
|
||||
|
||||
// 读指定长度数据
|
||||
BYTE *Ifstream_NPK::ReadCustomSize(int Size)
|
||||
{
|
||||
BYTE *CharBuffer = new BYTE[Size];
|
||||
for (int j = 0; j < Size; j++)
|
||||
{
|
||||
char var;
|
||||
this->get(var);
|
||||
CharBuffer[j] = var;
|
||||
}
|
||||
return CharBuffer;
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
class Ifstream_NPK : public std::ifstream
|
||||
{
|
||||
private:
|
||||
const BYTE Key[256];
|
||||
|
||||
public:
|
||||
// 构造函数
|
||||
Ifstream_NPK();
|
||||
|
||||
// char* 转整数
|
||||
int CharToInt(char *Str);
|
||||
|
||||
// char* 转Long
|
||||
long CharToLong(char *Str);
|
||||
|
||||
// 读整数
|
||||
int ReadInt();
|
||||
|
||||
// 读字符串
|
||||
std::string ReadString();
|
||||
|
||||
// 读取信息
|
||||
std::string ReadInfo();
|
||||
|
||||
// 读LONG
|
||||
int ReadLong();
|
||||
|
||||
// 读指定长度数据
|
||||
BYTE *ReadCustomSize(int Size);
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#include "Ifstream_PVF.h"
|
||||
|
||||
Ifstream_PVF::Ifstream_PVF(std::string fileName)
|
||||
{
|
||||
std::ifstream file(fileName, std::ios::binary | std::ios::in);
|
||||
if (file.is_open())
|
||||
{
|
||||
// 获取文件大小
|
||||
file.seekg(0, std::ios::end);
|
||||
std::streamsize length = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
// 直接调整vector大小并读取数据
|
||||
_Data.resize(static_cast<size_t>(length));
|
||||
if (file.read(_Data.data(), length))
|
||||
{
|
||||
SDL_Log("文件读取成功,大小: %ld bytes", length);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "文件读取不完整");
|
||||
_Data.clear();
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "无法打开文件: %s", fileName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Ifstream_PVF::~Ifstream_PVF()
|
||||
{
|
||||
// vector会自动释放内存,无需手动操作
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
#pragma once
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <SDL.h>
|
||||
#include <algorithm>
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
// 定义宏用于注册获取不同类型值的函数
|
||||
#define REGISTER_GET_FUNCTION(Type, FunctionName) \
|
||||
Type Get##FunctionName() \
|
||||
{ \
|
||||
char buffer[sizeof(Type)]; \
|
||||
read(buffer, sizeof(Type)); \
|
||||
Type result; \
|
||||
std::memcpy(&result, buffer, sizeof(Type)); \
|
||||
return result; \
|
||||
}
|
||||
class Ifstream_PVF
|
||||
{
|
||||
public:
|
||||
// 使用vector存储数据,替代char*
|
||||
std::vector<char> _Data;
|
||||
// 当前位置
|
||||
int _CurPos = 0;
|
||||
// 上一次读取的实际大小
|
||||
int _LastReadSize = 0;
|
||||
|
||||
public:
|
||||
Ifstream_PVF(std::string fileName);
|
||||
~Ifstream_PVF();
|
||||
|
||||
public:
|
||||
int tellg()
|
||||
{
|
||||
return _CurPos;
|
||||
}
|
||||
|
||||
// 获取数据大小
|
||||
int size() const
|
||||
{
|
||||
return static_cast<int>(_Data.size());
|
||||
}
|
||||
|
||||
void read(char *ptr, int size)
|
||||
{
|
||||
// 使用vector的size()作为最大长度
|
||||
if ((size + _CurPos) > static_cast<int>(_Data.size()))
|
||||
{
|
||||
size = static_cast<int>(_Data.size()) - _CurPos;
|
||||
}
|
||||
memcpy(ptr, _Data.data() + _CurPos, size);
|
||||
_CurPos += size;
|
||||
_LastReadSize = size;
|
||||
}
|
||||
|
||||
int gcount()
|
||||
{
|
||||
return _LastReadSize;
|
||||
}
|
||||
|
||||
void seek(int _jidx)
|
||||
{
|
||||
// 确保不会越界
|
||||
_CurPos = std::clamp(_jidx, 0, static_cast<int>(_Data.size()));
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int charPtrToInt(const char *bytes)
|
||||
{
|
||||
unsigned int result;
|
||||
std::memcpy(&result, bytes, sizeof(int));
|
||||
return result;
|
||||
}
|
||||
|
||||
void CrcDecode(const int Length, const int crc32)
|
||||
{
|
||||
int num = 0x81A79011;
|
||||
int originalPos = tellg(); // 保存初始位置
|
||||
for (int i = 0; i < Length; i += 4)
|
||||
{
|
||||
int Pos = tellg();
|
||||
char buffer[4];
|
||||
read(buffer, 4);
|
||||
unsigned int anInt = charPtrToInt(buffer);
|
||||
unsigned int val = (anInt ^ num ^ crc32);
|
||||
unsigned int jiemi = (val >> 6) | ((val << (32 - 6)) & 0xFFFFFFFF);
|
||||
|
||||
// 使用vector的data()获取数据指针
|
||||
if (Pos + 3 < static_cast<int>(_Data.size()))
|
||||
{
|
||||
_Data[Pos] = ((jiemi >> 0) & 0xFF);
|
||||
_Data[Pos + 1] = ((jiemi >> 8) & 0xFF);
|
||||
_Data[Pos + 2] = ((jiemi >> 16) & 0xFF);
|
||||
_Data[Pos + 3] = ((jiemi >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
// 重置读取位置,因为解码过程中移动了指针
|
||||
seek(originalPos + Length); // 移动到解码后的位置
|
||||
}
|
||||
|
||||
std::string tolower(std::string str)
|
||||
{
|
||||
for (size_t i = 0; i < str.length(); ++i)
|
||||
{
|
||||
str[i] = std::tolower(str[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string &str, const std::string &delimiter)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
size_t pos = 0;
|
||||
size_t found;
|
||||
while ((found = str.find(delimiter, pos)) != std::string::npos)
|
||||
{
|
||||
tokens.push_back(str.substr(pos, found - pos));
|
||||
pos = found + delimiter.length();
|
||||
}
|
||||
tokens.push_back(str.substr(pos));
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public:
|
||||
REGISTER_GET_FUNCTION(int, Int);
|
||||
REGISTER_GET_FUNCTION(short, Short);
|
||||
REGISTER_GET_FUNCTION(unsigned short, UShort);
|
||||
|
||||
std::string GetString(const int size)
|
||||
{
|
||||
if (size <= 0)
|
||||
return "";
|
||||
|
||||
// 确保不会读取超出范围的数据
|
||||
int readSize = std::min(size, static_cast<int>(_Data.size()) - _CurPos);
|
||||
std::string result(_Data.data() + _CurPos, readSize);
|
||||
_CurPos += readSize;
|
||||
_LastReadSize = readSize;
|
||||
|
||||
if (readSize != size)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "未能成功读取指定字节数的数据!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetStringNormal(const int size)
|
||||
{
|
||||
// 与GetString实现相同,可根据实际需求区分
|
||||
if (size <= 0)
|
||||
return "";
|
||||
|
||||
int readSize = std::min(size, static_cast<int>(_Data.size()) - _CurPos);
|
||||
std::string result(_Data.data() + _CurPos, readSize);
|
||||
_CurPos += readSize;
|
||||
_LastReadSize = readSize;
|
||||
|
||||
if (readSize != size)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "未能成功读取指定字节数的数据!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,462 @@
|
|||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 侵入式链表
|
||||
template <typename _PtrTy>
|
||||
class IntrusiveList
|
||||
{
|
||||
public:
|
||||
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
IntrusiveList()
|
||||
: first_(), last_()
|
||||
{
|
||||
}
|
||||
|
||||
~IntrusiveList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取首元素
|
||||
const value_type &GetFirst() const
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取首元素
|
||||
value_type &GetFirst()
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取尾元素
|
||||
const value_type &GetLast() const
|
||||
{
|
||||
return last_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取尾元素
|
||||
value_type &GetLast()
|
||||
{
|
||||
return last_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 链表是否为空
|
||||
inline bool IsEmpty() const
|
||||
{
|
||||
return first_ == nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表尾部添加对象
|
||||
void PushBack(reference child)
|
||||
{
|
||||
if (child->GetPrev())
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
if (child->GetNext())
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
|
||||
child->GetPrev() = last_;
|
||||
child->GetNext() = nullptr;
|
||||
|
||||
if (first_)
|
||||
{
|
||||
last_->GetNext() = child;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表头部添加对象
|
||||
void PushFront(reference child)
|
||||
{
|
||||
if (child->GetPrev())
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
if (child->GetNext())
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
|
||||
child->GetPrev() = nullptr;
|
||||
child->GetNext() = first_;
|
||||
|
||||
if (first_)
|
||||
{
|
||||
first_->GetPrev() = child;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表的对象前插入新对象
|
||||
void InsertBefore(reference child, reference before)
|
||||
{
|
||||
if (child->GetPrev())
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
if (child->GetNext())
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
|
||||
if (before->GetPrev())
|
||||
before->GetPrev()->GetNext() = child;
|
||||
else
|
||||
first_ = child;
|
||||
|
||||
child->GetPrev() = before->GetPrev();
|
||||
child->GetNext() = before;
|
||||
before->GetPrev() = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表的对象后插入新对象
|
||||
void InsertAfter(reference child, reference after)
|
||||
{
|
||||
if (child->GetPrev())
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
if (child->GetNext())
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
|
||||
if (after->GetNext())
|
||||
after->GetNext()->GetPrev() = child;
|
||||
else
|
||||
last_ = child;
|
||||
|
||||
child->GetNext() = after->GetNext();
|
||||
child->GetPrev() = after;
|
||||
after->GetNext() = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移除对象
|
||||
void Remove(reference child)
|
||||
{
|
||||
if (child->GetNext())
|
||||
{
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
}
|
||||
else
|
||||
{
|
||||
last_ = child->GetPrev();
|
||||
}
|
||||
|
||||
if (child->GetPrev())
|
||||
{
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
first_ = child->GetNext();
|
||||
}
|
||||
|
||||
child->GetPrev() = nullptr;
|
||||
child->GetNext() = nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 清空所有对象
|
||||
void Clear()
|
||||
{
|
||||
value_type p = first_;
|
||||
while (p)
|
||||
{
|
||||
value_type tmp = p;
|
||||
p = p->GetNext();
|
||||
if (tmp)
|
||||
{
|
||||
tmp->GetNext() = nullptr;
|
||||
tmp->GetPrev() = nullptr;
|
||||
}
|
||||
}
|
||||
first_ = nullptr;
|
||||
last_ = nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 检查链表是否有效
|
||||
bool CheckValid()
|
||||
{
|
||||
if (!first_)
|
||||
return true;
|
||||
|
||||
int pos = 0;
|
||||
|
||||
value_type p = first_;
|
||||
value_type tmp = p;
|
||||
do
|
||||
{
|
||||
tmp = p;
|
||||
p = p->GetNext();
|
||||
++pos;
|
||||
|
||||
if (p)
|
||||
{
|
||||
if (p->GetPrev() != tmp)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmp != last_)
|
||||
return false;
|
||||
}
|
||||
} while (p);
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename _IterPtrTy>
|
||||
struct Iterator
|
||||
{
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = _IterPtrTy;
|
||||
using pointer = _IterPtrTy *;
|
||||
using reference = _IterPtrTy &;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
inline Iterator(value_type ptr = nullptr, bool is_end = false)
|
||||
: base_(ptr), is_end_(is_end)
|
||||
{
|
||||
}
|
||||
|
||||
inline reference operator*() const
|
||||
{
|
||||
KGE_ASSERT(base_ && !is_end_);
|
||||
return const_cast<reference>(base_);
|
||||
}
|
||||
|
||||
inline pointer operator->() const
|
||||
{
|
||||
return std::pointer_traits<pointer>::pointer_to(**this);
|
||||
}
|
||||
|
||||
inline Iterator &operator++()
|
||||
{
|
||||
KGE_ASSERT(base_ && !is_end_);
|
||||
value_type next = base_->GetNext();
|
||||
if (next)
|
||||
base_ = next;
|
||||
else
|
||||
is_end_ = true;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Iterator operator++(int)
|
||||
{
|
||||
Iterator old = (*this);
|
||||
++(*this);
|
||||
return old;
|
||||
}
|
||||
|
||||
inline Iterator &operator--()
|
||||
{
|
||||
KGE_ASSERT(base_);
|
||||
if (is_end_)
|
||||
is_end_ = false;
|
||||
else
|
||||
base_ = base_->GetPrev();
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Iterator operator--(int)
|
||||
{
|
||||
Iterator old = (*this);
|
||||
--(*this);
|
||||
return old;
|
||||
}
|
||||
|
||||
inline bool operator==(const Iterator &other) const
|
||||
{
|
||||
return base_ == other.base_ && is_end_ == other.is_end_;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Iterator &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline operator bool() const
|
||||
{
|
||||
return base_ != nullptr && !is_end_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_end_;
|
||||
|
||||
typename std::remove_const<value_type>::type base_;
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = Iterator<value_type>;
|
||||
using const_iterator = Iterator<const value_type>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
inline iterator begin()
|
||||
{
|
||||
return iterator(first_, first_ == nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const
|
||||
{
|
||||
return const_iterator(first_, first_ == nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator cbegin() const
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
inline iterator end()
|
||||
{
|
||||
return iterator(last_, true);
|
||||
}
|
||||
|
||||
inline const_iterator end() const
|
||||
{
|
||||
return const_iterator(last_, true);
|
||||
}
|
||||
|
||||
inline const_iterator cend() const
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
inline reverse_iterator rbegin()
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator rbegin() const
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator crbegin() const
|
||||
{
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
inline reverse_iterator rend()
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator rend() const
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator crend() const
|
||||
{
|
||||
return rend();
|
||||
}
|
||||
|
||||
inline value_type &front()
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("front() called on empty list");
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline const value_type &front() const
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("front() called on empty list");
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline value_type &back()
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("back() called on empty list");
|
||||
return last_;
|
||||
}
|
||||
|
||||
inline const value_type &back() const
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("back() called on empty list");
|
||||
return last_;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type first_;
|
||||
value_type last_;
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 侵入式链表元素
|
||||
template <typename _PtrTy>
|
||||
class IntrusiveListValue
|
||||
{
|
||||
public:
|
||||
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
|
||||
using reference = value_type &;
|
||||
using pointer = value_type *;
|
||||
|
||||
IntrusiveListValue()
|
||||
: prev_(nullptr), next_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
IntrusiveListValue(value_type rhs)
|
||||
: prev_(nullptr), next_(nullptr)
|
||||
{
|
||||
if (rhs)
|
||||
{
|
||||
prev_ = rhs->GetPrev();
|
||||
next_ = rhs->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取前一元素
|
||||
const value_type &GetPrev() const
|
||||
{
|
||||
return prev_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取前一元素
|
||||
value_type &GetPrev()
|
||||
{
|
||||
return prev_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取下一元素
|
||||
const value_type &GetNext() const
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取下一元素
|
||||
value_type &GetNext()
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type prev_;
|
||||
value_type next_;
|
||||
|
||||
friend class IntrusiveList<_PtrTy>;
|
||||
};
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include "Tool/Common.h"
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 引用计数智能指针
|
||||
*/
|
||||
template <typename _Ty, typename _RefPolicy>
|
||||
class RefBasePtr : protected _RefPolicy
|
||||
{
|
||||
public:
|
||||
using value_type = _Ty;
|
||||
using pointer_type = _Ty *;
|
||||
using const_pointer_type = const _Ty *;
|
||||
using reference_type = _Ty &;
|
||||
using const_reference_type = const _Ty &;
|
||||
|
||||
RefBasePtr() noexcept
|
||||
: ptr_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
RefBasePtr(std::nullptr_t) noexcept
|
||||
: ptr_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
RefBasePtr(pointer_type p)
|
||||
: ptr_(p)
|
||||
{
|
||||
_RefPolicy::Retain(ptr_);
|
||||
}
|
||||
|
||||
RefBasePtr(const RefBasePtr &other)
|
||||
: ptr_(other.ptr_)
|
||||
{
|
||||
_RefPolicy::Retain(ptr_);
|
||||
}
|
||||
|
||||
RefBasePtr(RefBasePtr &&other) noexcept
|
||||
: ptr_(nullptr)
|
||||
{
|
||||
Swap(other);
|
||||
}
|
||||
|
||||
~RefBasePtr()
|
||||
{
|
||||
Tidy();
|
||||
}
|
||||
|
||||
template <typename _UTy, typename std::enable_if<std::is_convertible<_UTy *, _Ty *>::value, int>::type = 0>
|
||||
RefBasePtr(const RefBasePtr<_UTy, _RefPolicy> &other)
|
||||
{
|
||||
ptr_ = dynamic_cast<pointer_type>(other.Get());
|
||||
_RefPolicy::Retain(ptr_);
|
||||
}
|
||||
|
||||
inline pointer_type Get() const noexcept
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
inline pointer_type *GetAddressOfAndRelease()
|
||||
{
|
||||
Tidy();
|
||||
return &ptr_;
|
||||
}
|
||||
|
||||
inline void Reset(pointer_type ptr = nullptr)
|
||||
{
|
||||
if (ptr)
|
||||
RefBasePtr(ptr).Swap(*this);
|
||||
else
|
||||
Tidy();
|
||||
}
|
||||
|
||||
inline void Swap(RefBasePtr &other) noexcept
|
||||
{
|
||||
std::swap(ptr_, other.ptr_);
|
||||
}
|
||||
|
||||
inline pointer_type operator->()
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
inline const_pointer_type operator->() const
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
inline reference_type operator*()
|
||||
{
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
inline const_reference_type operator*() const
|
||||
{
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
inline pointer_type *operator&()
|
||||
{
|
||||
return this->GetAddressOfAndRelease();
|
||||
}
|
||||
|
||||
inline operator bool() const noexcept
|
||||
{
|
||||
return ptr_ != nullptr;
|
||||
}
|
||||
|
||||
inline bool operator!() const noexcept
|
||||
{
|
||||
return ptr_ == 0;
|
||||
}
|
||||
|
||||
inline RefBasePtr &operator=(const RefBasePtr &other)
|
||||
{
|
||||
if (other.ptr_ != ptr_)
|
||||
RefBasePtr(other).Swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline RefBasePtr &operator=(RefBasePtr &&other) noexcept
|
||||
{
|
||||
if (other.ptr_ != ptr_)
|
||||
other.Swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline RefBasePtr &operator=(pointer_type p)
|
||||
{
|
||||
if (p != ptr_)
|
||||
RefBasePtr(p).Swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
template <typename _UTy, typename std::enable_if<std::is_convertible<_UTy *, _Ty *>::value, int>::type = 0>
|
||||
inline RefBasePtr &operator=(const RefBasePtr<_UTy, _RefPolicy> &other)
|
||||
{
|
||||
if (other.Get() != ptr_)
|
||||
RefBasePtr(dynamic_cast<pointer_type>(other.Get())).Swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline RefBasePtr &operator=(std::nullptr_t)
|
||||
{
|
||||
Tidy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void Tidy()
|
||||
{
|
||||
_RefPolicy::Release(ptr_);
|
||||
ptr_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
pointer_type ptr_;
|
||||
};
|
||||
|
||||
template <class _Ty, class _UTy, class _RefPolicy>
|
||||
inline bool operator==(const RefBasePtr<_Ty, _RefPolicy> &lhs, const RefBasePtr<_UTy, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
return lhs.Get() == rhs.Get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator==(const RefBasePtr<_Ty, _RefPolicy> &lhs, _Ty *rhs) noexcept
|
||||
{
|
||||
return lhs.Get() == rhs;
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator==(_Ty *lhs, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
return lhs == rhs.Get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator==(const RefBasePtr<_Ty, _RefPolicy> &lhs, std::nullptr_t) noexcept
|
||||
{
|
||||
return !static_cast<bool>(lhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator==(std::nullptr_t, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
return !static_cast<bool>(rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _UTy, class _RefPolicy>
|
||||
inline bool operator!=(const RefBasePtr<_Ty, _RefPolicy> &lhs, const RefBasePtr<_UTy, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator!=(const RefBasePtr<_Ty, _RefPolicy> &lhs, _Ty *rhs) noexcept
|
||||
{
|
||||
return lhs.Get() != rhs;
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator!=(_Ty *lhs, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
return lhs != rhs.Get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator!=(const RefBasePtr<_Ty, _RefPolicy> &lhs, std::nullptr_t) noexcept
|
||||
{
|
||||
return static_cast<bool>(lhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline bool operator!=(std::nullptr_t, const RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
return static_cast<bool>(rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _UTy, class _RefPolicy>
|
||||
inline bool operator<(const RefBasePtr<_Ty, _RefPolicy> &lhs, const RefBasePtr<_UTy, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
return lhs.Get() < rhs.Get();
|
||||
}
|
||||
|
||||
// template class cannot specialize std::swap,
|
||||
// so implement a swap function in kiwano namespace
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline void swap(RefBasePtr<_Ty, _RefPolicy> &lhs, RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
lhs.Swap(rhs);
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#include "Tool/RefObject.h"
|
||||
|
||||
RefObject::RefObject()
|
||||
: ref_count_(0) // 修正:新创建对象引用计数应为1
|
||||
{
|
||||
}
|
||||
|
||||
RefObject::~RefObject() {}
|
||||
|
||||
void RefObject::Retain()
|
||||
{
|
||||
// 修正:使用fetch_add确保原子操作
|
||||
ref_count_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void RefObject::Release()
|
||||
{
|
||||
// 修正:使用fetch_sub确保原子操作并检查结果
|
||||
if (ref_count_.fetch_sub(1, std::memory_order_acq_rel) == 1)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RefObject::GetRefCount() const
|
||||
{
|
||||
return ref_count_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void *RefObject::operator new(size_t size)
|
||||
{
|
||||
void *ptr = memory::Alloc(size);
|
||||
if (!ptr)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void RefObject::operator delete(void *ptr)
|
||||
{
|
||||
if (ptr) // 增加空指针检查
|
||||
{
|
||||
memory::Free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// 修正:添加noexcept说明符,与声明一致
|
||||
void *RefObject::operator new(size_t size, std::nothrow_t const &) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
return memory::Alloc(size);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// 修正:添加noexcept说明符,与声明一致
|
||||
void RefObject::operator delete(void *ptr, std::nothrow_t const &) noexcept
|
||||
{
|
||||
if (ptr) // 增加空指针检查
|
||||
{
|
||||
try
|
||||
{
|
||||
memory::Free(ptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// 忽略异常,符合noexcept语义
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修正:添加noexcept说明符,与声明一致
|
||||
void *RefObject::operator new(size_t size, void *ptr) noexcept
|
||||
{
|
||||
return ::operator new(size, ptr);
|
||||
}
|
||||
|
||||
void RefObject::operator delete(void *ptr, void *place) noexcept
|
||||
{
|
||||
::operator delete(ptr, place);
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include "Tool/Common.h"
|
||||
#include "Tool/Allocator.h"
|
||||
#include <atomic>
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 引用计数器
|
||||
*/
|
||||
class RefObject : protected Noncopyable
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 增加引用计数
|
||||
void Retain();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 减少引用计数
|
||||
void Release();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取引用计数
|
||||
uint32_t GetRefCount() const;
|
||||
|
||||
static void *operator new(size_t size);
|
||||
|
||||
static void operator delete(void *ptr);
|
||||
|
||||
static void *operator new(size_t size, std::nothrow_t const &) noexcept;
|
||||
|
||||
static void operator delete(void *ptr, std::nothrow_t const &) noexcept;
|
||||
|
||||
static void *operator new(size_t size, void *ptr) noexcept;
|
||||
|
||||
static void operator delete(void *ptr, void *place) noexcept;
|
||||
|
||||
virtual ~RefObject();
|
||||
|
||||
protected:
|
||||
RefObject();
|
||||
|
||||
private:
|
||||
std::atomic<uint32_t> ref_count_;
|
||||
};
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include "Tool/RefObject.h"
|
||||
#include "Tool/RefBasePtr.hpp"
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 默认的智能指针引用计数策略
|
||||
struct DefaultRefPtrPolicy
|
||||
{
|
||||
inline void Retain(RefObject *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->Retain();
|
||||
}
|
||||
|
||||
inline void Release(RefObject *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->Release();
|
||||
}
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 引用计数对象智能指针
|
||||
template <typename _Ty>
|
||||
using RefPtr = RefBasePtr<_Ty, DefaultRefPtrPolicy>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 构造引用计数对象智能指针
|
||||
template <typename _Ty, typename... _Args>
|
||||
inline RefPtr<_Ty> MakePtr(_Args &&...args)
|
||||
{
|
||||
static_assert(std::is_base_of<RefObject, _Ty>::value, "_Ty must be derived from RefObject");
|
||||
return RefPtr<_Ty>(new _Ty(std::forward<_Args>(args)...));
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 构造引用计数对象智能指针
|
||||
template <typename _Ty>
|
||||
inline RefPtr<_Ty> MakePtr(_Ty *ptr)
|
||||
{
|
||||
static_assert(std::is_base_of<RefObject, _Ty>::value, "_Ty must be derived from RefObject");
|
||||
return RefPtr<_Ty>(ptr);
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#include "RemoteLogger.h"
|
||||
|
||||
RemoteLogger::RemoteLogger() : sockfd(-1), is_initialized(false)
|
||||
{
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_len = sizeof(server_addr);
|
||||
}
|
||||
|
||||
RemoteLogger::~RemoteLogger()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool RemoteLogger::Init(const char *target_ip, unsigned short target_port)
|
||||
{
|
||||
// 如果已经初始化,先关闭
|
||||
if (is_initialized)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
// 创建UDP socket
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 设置服务器地址
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(target_port);
|
||||
|
||||
// 转换IP地址
|
||||
if (inet_pton(AF_INET, target_ip, &server_addr.sin_addr) <= 0)
|
||||
{
|
||||
::close(sockfd);
|
||||
sockfd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
is_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string RemoteLogger::format_string(const char *format, va_list vl)
|
||||
{
|
||||
// 第一次调用:获取所需缓冲区大小
|
||||
va_list vl_copy;
|
||||
va_copy(vl_copy, vl); // 复制 va_list(关键!避免原 vl 被修改)
|
||||
int length = vsnprintf(nullptr, 0, format, vl_copy);
|
||||
va_end(vl_copy); // 释放复制的 va_list
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
return "Format error"; // 格式化失败时返回明确信息
|
||||
}
|
||||
|
||||
// 第二次调用:实际格式化字符串
|
||||
std::vector<char> buffer(length + 1); // 用 vector 自动管理内存
|
||||
vsnprintf(buffer.data(), buffer.size(), format, vl);
|
||||
return std::string(buffer.data()); // 直接返回,无需手动移除空字符
|
||||
}
|
||||
void RemoteLogger::log(const char *format, ...)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
|
||||
std::string message = format_string(format, vl);
|
||||
va_end(vl);
|
||||
|
||||
// 先输出到SDL日志
|
||||
SDL_Log(message.c_str());
|
||||
if (!is_initialized || sockfd < 0)
|
||||
return;
|
||||
|
||||
// 通过UDP发送
|
||||
sendto(sockfd, message.c_str(), message.size(), 0,
|
||||
(struct sockaddr *)&server_addr, server_len);
|
||||
}
|
||||
|
||||
void RemoteLogger::close()
|
||||
{
|
||||
if (sockfd >= 0)
|
||||
{
|
||||
::close(sockfd);
|
||||
sockfd = -1;
|
||||
}
|
||||
is_initialized = false;
|
||||
}
|
||||
// 检查是否已初始化
|
||||
bool RemoteLogger::isInitialized() const
|
||||
{
|
||||
return is_initialized;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <switch.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <SDL.h>
|
||||
#include <vector>
|
||||
|
||||
class RemoteLogger
|
||||
{
|
||||
public:
|
||||
RemoteLogger(const RemoteLogger &) = delete;
|
||||
RemoteLogger &operator=(const RemoteLogger &) = delete;
|
||||
RemoteLogger(RemoteLogger &&) = delete;
|
||||
RemoteLogger &operator=(RemoteLogger &&) = delete;
|
||||
// 全局访问点
|
||||
static RemoteLogger &GetInstance()
|
||||
{
|
||||
static RemoteLogger instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
// 安全格式化到字符串
|
||||
static std::string format_string(const char *format, va_list vl);
|
||||
|
||||
public:
|
||||
// 初始化函数,返回是否成功
|
||||
bool Init(const char *target_ip, unsigned short target_port);
|
||||
// 日志输出函数,支持格式化字符串
|
||||
void log(const char *format, ...);
|
||||
// 关闭连接
|
||||
void close();
|
||||
// 检查是否已初始化
|
||||
bool isInitialized() const;
|
||||
|
||||
private:
|
||||
RemoteLogger(/* args */);
|
||||
~RemoteLogger();
|
||||
|
||||
int sockfd = -1;
|
||||
struct sockaddr_in server_addr;
|
||||
socklen_t server_len;
|
||||
bool is_initialized = false;
|
||||
};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
enum class Tag
|
||||
{
|
||||
NONE = 0, // 无标签
|
||||
UPDATE = 1 << 0, // 更新标签
|
||||
RENDER = 1 << 1, // 渲染标签
|
||||
};
|
||||
|
||||
constexpr Tag operator|(Tag a, Tag b)
|
||||
{
|
||||
using Underlying = std::underlying_type_t<Tag>;
|
||||
return static_cast<Tag>(static_cast<Underlying>(a) | static_cast<Underlying>(b));
|
||||
}
|
||||
|
||||
constexpr Tag operator&(Tag a, Tag b)
|
||||
{
|
||||
using Underlying = std::underlying_type_t<Tag>;
|
||||
return static_cast<Tag>(static_cast<Underlying>(a) & static_cast<Underlying>(b));
|
||||
}
|
||||
class TagGed
|
||||
{
|
||||
private:
|
||||
uint64_t m_tags;
|
||||
|
||||
public:
|
||||
TagGed(Tag initialTag = Tag::NONE)
|
||||
: m_tags(static_cast<uint64_t>(initialTag)) {}
|
||||
|
||||
// 添加标签
|
||||
void addTag(Tag tag)
|
||||
{
|
||||
m_tags |= static_cast<uint64_t>(tag);
|
||||
}
|
||||
|
||||
// 移除标签
|
||||
void removeTag(Tag tag)
|
||||
{
|
||||
m_tags &= ~static_cast<uint64_t>(tag);
|
||||
}
|
||||
|
||||
// 判断是否包含指定标签
|
||||
bool hasTag(Tag tag) const
|
||||
{
|
||||
return (m_tags & static_cast<uint64_t>(tag)) != 0;
|
||||
}
|
||||
|
||||
// 判断是否包含所有指定标签
|
||||
bool hasAllTags(Tag tags) const
|
||||
{
|
||||
return (m_tags & static_cast<uint64_t>(tags)) == static_cast<uint64_t>(tags);
|
||||
}
|
||||
|
||||
// 清除所有标签
|
||||
void clearTags()
|
||||
{
|
||||
m_tags = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
#include "ThreadPool.h"
|
||||
#include <stdexcept>
|
||||
#include <cstdio>
|
||||
|
||||
// 获取单例实例
|
||||
ThreadPool &ThreadPool::GetInstance()
|
||||
{
|
||||
static ThreadPool instance(3); // 固定3个工作线程
|
||||
return instance;
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool()
|
||||
{
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void ThreadPool::shutdown()
|
||||
{
|
||||
printf("ThreadPool destroyed\n");
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
stop = true;
|
||||
// 清空所有线程的任务队列
|
||||
for (auto &queue : threadTasks)
|
||||
{
|
||||
// 使用swap技巧清空队列
|
||||
std::queue<std::function<void()>> empty;
|
||||
std::swap(queue, empty);
|
||||
}
|
||||
}
|
||||
|
||||
// 通知所有线程
|
||||
for (auto &cond : threadConditions)
|
||||
cond->notify_all();
|
||||
|
||||
for (std::thread &worker : workers)
|
||||
if (worker.joinable())
|
||||
worker.join();
|
||||
|
||||
// 释放条件变量
|
||||
for (auto &cond : threadConditions)
|
||||
delete cond;
|
||||
}
|
||||
|
||||
// 获取线程池大小
|
||||
size_t ThreadPool::size() const
|
||||
{
|
||||
return workers.size();
|
||||
}
|
||||
|
||||
// 获取指定线程的负载(待处理任务数)
|
||||
size_t ThreadPool::getThreadLoad(int threadId) const
|
||||
{
|
||||
if (threadId < 0 || threadId >= static_cast<int>(workers.size()))
|
||||
throw std::runtime_error("Invalid thread ID");
|
||||
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
return threadTasks.at(threadId).size();
|
||||
}
|
||||
|
||||
// 私有构造函数实现
|
||||
ThreadPool::ThreadPool(size_t numThreads) : stop(false)
|
||||
{
|
||||
// 为每个线程创建任务队列
|
||||
threadTasks.resize(numThreads);
|
||||
|
||||
// 为每个线程创建条件变量
|
||||
for (size_t i = 0; i < numThreads; ++i)
|
||||
{
|
||||
threadConditions.push_back(new std::condition_variable());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < numThreads; ++i)
|
||||
{
|
||||
workers.emplace_back([this, i]
|
||||
{
|
||||
while(true) {
|
||||
std::function<void()> task;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
this->threadConditions[i]->wait(lock, [this, i] {
|
||||
return this->stop || !this->threadTasks[i].empty();
|
||||
});
|
||||
|
||||
if(this->stop && this->threadTasks[i].empty())
|
||||
return;
|
||||
|
||||
task = std::move(this->threadTasks[i].front());
|
||||
this->threadTasks[i].pop();
|
||||
}
|
||||
|
||||
task();
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
class ThreadPool
|
||||
{
|
||||
public:
|
||||
// 获取单例实例
|
||||
static ThreadPool &GetInstance();
|
||||
|
||||
// 删除拷贝构造函数和赋值运算符
|
||||
ThreadPool(const ThreadPool &) = delete;
|
||||
ThreadPool &operator=(const ThreadPool &) = delete;
|
||||
|
||||
// 向指定线程添加任务
|
||||
template <class F, class... Args>
|
||||
void enqueueToThread(int threadId, F &&f, Args &&...args)
|
||||
{
|
||||
if (threadId < 0 || threadId >= static_cast<int>(workers.size()))
|
||||
throw std::runtime_error("Invalid thread ID");
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
|
||||
// 不允许在停止后添加新任务
|
||||
if (stop)
|
||||
throw std::runtime_error("enqueue on stopped ThreadPool");
|
||||
|
||||
// 将任务添加到指定线程的队列
|
||||
threadTasks[threadId].emplace([=]() mutable
|
||||
{ std::invoke(f, args...); });
|
||||
}
|
||||
|
||||
// 通知指定线程
|
||||
threadConditions[threadId]->notify_one();
|
||||
}
|
||||
|
||||
// 向任意线程添加任务(负载均衡)
|
||||
template <class F, class... Args>
|
||||
void enqueue(F &&f, Args &&...args)
|
||||
{
|
||||
// 使用轮询方式选择线程
|
||||
static std::atomic<int> nextThreadId(0);
|
||||
int threadId = nextThreadId.load();
|
||||
nextThreadId = (nextThreadId + 1) % workers.size();
|
||||
|
||||
enqueueToThread(threadId, std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
~ThreadPool();
|
||||
|
||||
void shutdown();
|
||||
|
||||
// 获取线程池大小
|
||||
size_t size() const;
|
||||
|
||||
// 获取指定线程的负载(待处理任务数)
|
||||
size_t getThreadLoad(int threadId) const;
|
||||
|
||||
private:
|
||||
// 私有构造函数
|
||||
ThreadPool(size_t numThreads);
|
||||
|
||||
private:
|
||||
std::vector<std::thread> workers;
|
||||
std::vector<std::queue<std::function<void()>>> threadTasks; // 每个线程有自己的任务队列
|
||||
|
||||
mutable std::mutex queue_mutex;
|
||||
std::vector<std::condition_variable *> threadConditions; // 使用指针存储条件变量
|
||||
std::atomic<bool> stop;
|
||||
};
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#include "Tool/Tool_Network.h"
|
||||
|
||||
// 定义内存管理结构体
|
||||
struct MemoryStruct
|
||||
{
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
|
||||
|
||||
void *ptr = realloc(mem->memory, mem->size + realsize + 1);
|
||||
if (!ptr)
|
||||
{
|
||||
RemoteLogger::GetInstance().log("内存分配失败 (out of memory)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem->memory = (char *)ptr;
|
||||
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = '\0';
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
int http_get(const char *url, char **response, size_t *response_size)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct MemoryStruct chunk;
|
||||
|
||||
// 初始化内存结构
|
||||
chunk.memory = (char *)malloc(1);
|
||||
chunk.size = 0;
|
||||
if (!chunk.memory)
|
||||
{
|
||||
RemoteLogger::GetInstance().log("初始内存分配失败");
|
||||
return -1;
|
||||
}
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (curl)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||
|
||||
// 允许重定向
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
|
||||
|
||||
// 执行请求
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
// 检查HTTP状态码
|
||||
long response_code;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
// RemoteLogger::GetInstance().log("HTTP 状态码: %ld");
|
||||
|
||||
if (res != CURLE_OK)
|
||||
{
|
||||
RemoteLogger::GetInstance().log("请求失败: %s", curl_easy_strerror(res));
|
||||
free(chunk.memory);
|
||||
*response = NULL;
|
||||
*response_size = 0;
|
||||
curl_easy_cleanup(curl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 返回结果
|
||||
*response = chunk.memory;
|
||||
*response_size = chunk.size;
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(chunk.memory);
|
||||
*response = NULL;
|
||||
*response_size = 0;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <curl/curl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "Tool/RemoteLogger.h"
|
||||
|
||||
// 回调函数
|
||||
size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp);
|
||||
|
||||
// HTTP GET请求函数
|
||||
int http_get(const char *url, char **response, size_t *response_size);
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
std::string Tool_toLowerCase(const std::string &str)
|
||||
{
|
||||
std::string result = str;
|
||||
// 使用transform算法遍历字符串并转换为小写
|
||||
std::transform(result.begin(), result.end(), result.begin(),
|
||||
[](unsigned char c)
|
||||
{ return std::tolower(c); });
|
||||
return result;
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
// 电脑的IP地址和端口
|
||||
#define PC_IP "192.168.200.3"
|
||||
#define PC_SCRIPT_PORT "39018"
|
||||
#define PC_LOG_PORT 39019
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <switch.h>
|
||||
#include <sys/socket.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "EngineCore/Asset_ImagePack.h"
|
||||
#include "EngineCore/Asset_Script.h"
|
||||
#include "squirrel/SquirrelEx.h"
|
||||
#include "Tool/RemoteLogger.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "Scene/Scene_Loading_UI.h"
|
||||
#include "Tool/RefPtr.h"
|
||||
#include "Global/Global_Game.h"
|
||||
#include "Tool/ThreadPool.h"
|
||||
|
||||
void InitScript()
|
||||
{
|
||||
SDL_Log("开始初始化PVF");
|
||||
// 初始化脚本资源系统
|
||||
Asset_Script::GetInstance().Init();
|
||||
SDL_Log("PVF初始化完成!");
|
||||
}
|
||||
|
||||
void RunSetup()
|
||||
{
|
||||
// 初始化Squirrel脚本系统
|
||||
SquirrelEx::GetInstance().Run();
|
||||
// 初始化全局游戏类
|
||||
Global_Game::GetInstance().Init();
|
||||
|
||||
// 设定UI层场景
|
||||
RefPtr<Scene_Loading_UI> sceneUI = new Scene_Loading_UI;
|
||||
Game::GetInstance().ChangeUIScene(sceneUI);
|
||||
|
||||
ThreadPool::GetInstance().enqueue(InitScript);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
socketInitializeDefault();
|
||||
nxlinkStdio(); // 启用nxlink调试输出
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT); // 初始化libcurl
|
||||
chdir("/switch/Lenheart/MyGame/");
|
||||
|
||||
// 初始化Image资源系统
|
||||
Asset_ImagePack::GetInstance().Init();
|
||||
// 初始化脚本资源系统
|
||||
Asset_Script::GetInstance();
|
||||
// 初始化线程池
|
||||
ThreadPool::GetInstance();
|
||||
|
||||
// 初始化日志系统
|
||||
if (RemoteLogger::GetInstance().Init(PC_IP, PC_LOG_PORT))
|
||||
{
|
||||
RemoteLogger::GetInstance().log("日志系统初始化成功!\n");
|
||||
}
|
||||
|
||||
// 初始化Squirrel脚本系统
|
||||
SquirrelEx::GetInstance().Init();
|
||||
// 请求脚本
|
||||
SquirrelEx::GetInstance().RequestNetScript(PC_IP, PC_SCRIPT_PORT);
|
||||
|
||||
// 初始化游戏引擎
|
||||
Game &game = Game::GetInstance();
|
||||
// 初始化各项目
|
||||
game.Init(RunSetup);
|
||||
// 进入游戏循环逻辑
|
||||
game.Run();
|
||||
game.Clear();
|
||||
|
||||
ThreadPool::GetInstance().shutdown();
|
||||
socketExit();
|
||||
curl_global_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#include "SquirrelEx.h"
|
||||
#include "Tool/RemoteLogger.h"
|
||||
#include "squirrel/sqr_sdl.hpp"
|
||||
SquirrelEx::SquirrelEx()
|
||||
{
|
||||
}
|
||||
SquirrelEx::~SquirrelEx()
|
||||
{
|
||||
}
|
||||
void SquirrelEx::printfunc(HSQUIRRELVM v, const SQChar *s, ...)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, s);
|
||||
std::string message = RemoteLogger::format_string(s, vl);
|
||||
va_end(vl);
|
||||
RemoteLogger::GetInstance().log(message.c_str());
|
||||
}
|
||||
|
||||
void SquirrelEx::errorfunc(HSQUIRRELVM v, const SQChar *s, ...)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, s);
|
||||
std::string message = RemoteLogger::format_string(s, vl);
|
||||
va_end(vl);
|
||||
RemoteLogger::GetInstance().log(message.c_str());
|
||||
}
|
||||
|
||||
bool SquirrelEx::Compilebuffer(std::string Path, std::string Code)
|
||||
{
|
||||
if (v == nullptr)
|
||||
{
|
||||
RemoteLogger::GetInstance().log("松鼠虚拟机未初始化!");
|
||||
return false;
|
||||
}
|
||||
if (sq_compilebuffer(v, Code.c_str(), Code.length(), Path.c_str(), SQTrue) >= 0)
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_call(v, 1, SQFalse, SQTrue);
|
||||
sq_pop(v, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SquirrelEx::Init()
|
||||
{
|
||||
v = sq_open(1024); // 栈大小1024
|
||||
sqstd_seterrorhandlers(v);
|
||||
sq_pushroottable(v);
|
||||
sqstd_register_bloblib(v);
|
||||
sqstd_register_iolib(v);
|
||||
sqstd_register_systemlib(v);
|
||||
sqstd_register_mathlib(v);
|
||||
sqstd_register_stringlib(v);
|
||||
|
||||
sq_setprintfunc(v, printfunc, errorfunc);
|
||||
RegisterSDLFunctions(v);
|
||||
}
|
||||
|
||||
void SquirrelEx::RequestNetScript(std::string Ip, std::string Port)
|
||||
{
|
||||
char *response = NULL;
|
||||
size_t response_size = 0;
|
||||
std::string url = "http://" + Ip + ":" + Port + "/get/getadvertisement?key=Files"; // 确保协议正确
|
||||
int result = http_get(url.c_str(), &response, &response_size);
|
||||
if (result == 0 && response != NULL && response_size > 0)
|
||||
{
|
||||
std::string response_str(response, response_size);
|
||||
free(response); // 释放内存
|
||||
nlohmann::json ex1 = nlohmann::json::parse(response_str);
|
||||
for (const auto &[key, value] : ex1.items())
|
||||
{
|
||||
std::string key_str = key;
|
||||
std::string value_str = value;
|
||||
bool Flag = Compilebuffer(key_str, value_str);
|
||||
if (!Flag)
|
||||
{
|
||||
RemoteLogger::GetInstance().log("Squirrel Compilebuffer Error! FileName: %s", key_str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (response)
|
||||
free(response);
|
||||
}
|
||||
}
|
||||
|
||||
void SquirrelEx::Run()
|
||||
{
|
||||
// 载入main函数
|
||||
SQInteger top = sq_gettop(v); // saves the stack size before the call
|
||||
sq_pushroottable(v); // pushes the global table
|
||||
sq_pushstring(v, _SC("main"), -1);
|
||||
if (SQ_SUCCEEDED(sq_get(v, -2)))
|
||||
{ // gets the field 'foo' from the global table
|
||||
sq_pushroottable(v); // push the 'this' (in this case is the global table)
|
||||
sq_call(v, 1, SQFalse, SQTrue); // calls the function
|
||||
}
|
||||
sq_settop(v, top); // restores the original stack size
|
||||
}
|
||||
|
||||
void SquirrelEx::UiRender(float deltaTime)
|
||||
{
|
||||
SQInteger top = sq_gettop(v);
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, _SC("UI_Render"), -1);
|
||||
if (SQ_SUCCEEDED(sq_get(v, -2)))
|
||||
{
|
||||
sq_pushroottable(v);
|
||||
sq_pushfloat(v, deltaTime);
|
||||
sq_call(v, 2, SQFalse, SQTrue);
|
||||
}
|
||||
sq_settop(v, top);
|
||||
}
|
||||
|
||||
void SquirrelEx::Clean()
|
||||
{
|
||||
sq_close(v);
|
||||
v = nullptr;
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <squirrel.h> // Squirrel核心头文件
|
||||
#include <sqstdio.h> // Squirrel标准IO库
|
||||
#include <sqstdaux.h> // 新增:包含 sqstd_seterrorhandlers 等辅助函数
|
||||
#include <sqstdblob.h> // 新增:包含 sqstd_register_bloblib 函数
|
||||
#include <sqstdsystem.h> // 新增:包含 sqstd_register_systemlib 函数
|
||||
#include <sqstdmath.h> // 新增:包含 sqstd_register_mathlib 函数
|
||||
#include <sqstdstring.h> // 新增:包含 sqstd_register_stringlib 函数
|
||||
#include <stdarg.h>
|
||||
#include <json.hpp>
|
||||
|
||||
#include "Tool/Tool_Network.h"
|
||||
|
||||
#ifdef SQUNICODE
|
||||
|
||||
#define scvprintf vfwprintf
|
||||
#else
|
||||
|
||||
#define scvprintf vfprintf
|
||||
#endif
|
||||
|
||||
class SquirrelEx
|
||||
{
|
||||
public:
|
||||
SquirrelEx(const SquirrelEx &) = delete;
|
||||
SquirrelEx &operator=(const SquirrelEx &) = delete;
|
||||
SquirrelEx(SquirrelEx &&) = delete;
|
||||
SquirrelEx &operator=(SquirrelEx &&) = delete;
|
||||
// 全局访问点
|
||||
static SquirrelEx &GetInstance()
|
||||
{
|
||||
static SquirrelEx instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
// 打印控制台
|
||||
static void printfunc(HSQUIRRELVM v, const SQChar *s, ...);
|
||||
// 错误打印控制台
|
||||
static void errorfunc(HSQUIRRELVM v, const SQChar *s, ...);
|
||||
// 从字符串编译Sqr脚本
|
||||
bool Compilebuffer(std::string Path, std::string Code);
|
||||
|
||||
public:
|
||||
// 初始化
|
||||
void Init();
|
||||
// 请求网络脚本
|
||||
void RequestNetScript(std::string Ip, std::string Port);
|
||||
// 运行
|
||||
void Run();
|
||||
// UiRender入口
|
||||
void UiRender(float deltaTime);
|
||||
// 清理
|
||||
void Clean();
|
||||
|
||||
private:
|
||||
SquirrelEx(/* args */);
|
||||
~SquirrelEx();
|
||||
HSQUIRRELVM v = nullptr;
|
||||
};
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <squirrel.h> // Squirrel核心头文件
|
||||
#include <sqstdio.h> // Squirrel标准IO库
|
||||
#include <sqstdaux.h> // 新增:包含 sqstd_seterrorhandlers 等辅助函数
|
||||
#include <sqstdblob.h> // 新增:包含 sqstd_register_bloblib 函数
|
||||
#include <sqstdsystem.h> // 新增:包含 sqstd_register_systemlib 函数
|
||||
#include <sqstdmath.h> // 新增:包含 sqstd_register_mathlib 函数
|
||||
#include <sqstdstring.h> // 新增:包含 sqstd_register_stringlib 函数
|
||||
#include "EngineCore/Asset_ImagePack.h"
|
||||
#include "EngineCore/Game.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
// 辅助函数:检查SDL错误并抛出Squirrel异常
|
||||
static void checkSDLError(HSQUIRRELVM v)
|
||||
{
|
||||
const char *err = SDL_GetError();
|
||||
if (err && *err)
|
||||
{
|
||||
sq_throwerror(v, err);
|
||||
SDL_ClearError();
|
||||
}
|
||||
}
|
||||
|
||||
// SDL_GetTicks 绑定
|
||||
static SQInteger sdl_GetTicks(HSQUIRRELVM v)
|
||||
{
|
||||
sq_pushinteger(v, SDL_GetTicks());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger sdl_CreateTexture(HSQUIRRELVM v)
|
||||
{
|
||||
const SQChar *imgPath;
|
||||
SQInteger Index;
|
||||
sq_getstring(v, 2, &imgPath);
|
||||
sq_getinteger(v, 3, &Index);
|
||||
|
||||
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(imgPath);
|
||||
Asset_ImagePack::ImgInfo &Buf = Info->lp_lplist[Index];
|
||||
SDL_Texture *m_texture = SDL_CreateTexture(
|
||||
Game::GetInstance().GetRenderer(),
|
||||
SDL_PIXELFORMAT_ARGB8888, // 匹配RGBA数据格式
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
Buf.Width, Buf.Height);
|
||||
int pitch = Buf.Width * 4;
|
||||
SDL_UpdateTexture(m_texture, NULL, Buf.PNGdata, pitch);
|
||||
|
||||
sq_pushuserpointer(v, m_texture);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger sdl_DrawImg(HSQUIRRELVM v)
|
||||
{
|
||||
SQUserPointer m_texture;
|
||||
SQInteger PosX, PosY, Width, Height;
|
||||
|
||||
sq_getuserpointer(v, 2, &m_texture);
|
||||
sq_getinteger(v, 3, &PosX);
|
||||
sq_getinteger(v, 4, &PosY);
|
||||
sq_getinteger(v, 5, &Width);
|
||||
sq_getinteger(v, 6, &Height);
|
||||
|
||||
SDL_Rect Rect = {(int)PosX, (int)PosY, (int)Width, (int)Height};
|
||||
SDL_RenderCopy(Game::GetInstance().GetRenderer(), (SDL_Texture *)m_texture, NULL, &Rect);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SQInteger sdl_DrawImgEx(HSQUIRRELVM v)
|
||||
{
|
||||
const SQChar *imgPath;
|
||||
SQInteger Index, PosX, PosY, BlendMode;
|
||||
SQFloat Rotate;
|
||||
|
||||
sq_getstring(v, 2, &imgPath);
|
||||
sq_getinteger(v, 3, &Index);
|
||||
sq_getinteger(v, 4, &PosX);
|
||||
sq_getinteger(v, 5, &PosY);
|
||||
sq_getinteger(v, 6, &BlendMode);
|
||||
sq_getfloat(v, 7, &Rotate);
|
||||
|
||||
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(imgPath);
|
||||
Asset_ImagePack::ImgInfo &Buf = Info->lp_lplist[Index];
|
||||
SDL_Point pivotPoint = {
|
||||
(int)(0.5 * Buf.Width),
|
||||
(int)(0.5 * Buf.Height)};
|
||||
|
||||
SDL_Texture *m_texture = SDL_CreateTexture(
|
||||
Game::GetInstance().GetRenderer(),
|
||||
SDL_PIXELFORMAT_ARGB8888, // 匹配RGBA数据格式
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
Buf.Width, Buf.Height);
|
||||
SDL_SetTextureBlendMode(m_texture, (SDL_BlendMode)BlendMode);
|
||||
int pitch = Buf.Width * 4;
|
||||
SDL_UpdateTexture(m_texture, NULL, Buf.PNGdata, pitch);
|
||||
SDL_Rect Rect = {(int)PosX, (int)PosY, Buf.Width, Buf.Height};
|
||||
SDL_RenderCopyEx(Game::GetInstance().GetRenderer(), m_texture, NULL, &Rect, Rotate, &pivotPoint, SDL_FLIP_NONE);
|
||||
SDL_DestroyTexture(m_texture);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterSDLFunctions(HSQUIRRELVM v)
|
||||
{
|
||||
// 创建SDL命名空间
|
||||
sq_pushstring(v, "SDL", -1);
|
||||
sq_newtable(v);
|
||||
|
||||
// 注册SDL函数
|
||||
|
||||
// 获取Ticks函数
|
||||
sq_pushstring(v, "GetTicks", -1);
|
||||
sq_newclosure(v, sdl_GetTicks, 0);
|
||||
sq_setparamscheck(v, 1, NULL);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// 创建纹理
|
||||
sq_pushstring(v, "CreateTexture", -1);
|
||||
sq_newclosure(v, sdl_CreateTexture, 0);
|
||||
// sq_setparamscheck(v, 3, NULL);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// 渲染一个Img
|
||||
sq_pushstring(v, "DrawImg", -1);
|
||||
sq_newclosure(v, sdl_DrawImg, 0);
|
||||
// sq_setparamscheck(v, 5, NULL);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// 渲染一个ImgEx
|
||||
sq_pushstring(v, "DrawImgEx", -1);
|
||||
sq_newclosure(v, sdl_DrawImgEx, 0);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// 注册SDL常量
|
||||
|
||||
sq_pushstring(v, "RENDERER_ACCELERATED", -1);
|
||||
sq_pushinteger(v, SDL_RENDERER_ACCELERATED);
|
||||
sq_rawset(v, -3);
|
||||
|
||||
// 将SDL表添加到全局命名空间
|
||||
sq_rawset(v, -3);
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <unordered_map>
|
||||
#include <SDL.h>
|
||||
|
||||
using AniFlag = std::variant<
|
||||
int,
|
||||
float,
|
||||
SDL_Point,
|
||||
SDL_FPoint,
|
||||
std::string,
|
||||
std::vector<int>,
|
||||
std::vector<float>>;
|
||||
struct AniFrame
|
||||
{
|
||||
std::string Img_Path; // img路径
|
||||
int Img_Index; // img索引
|
||||
SDL_Point Img_Pos; // img位置
|
||||
std::vector<std::vector<int>> AttackBox; // 攻击框
|
||||
std::vector<std::vector<int>> DamageBox; // 受击框
|
||||
std::unordered_map<std::string, AniFlag> Flag; // Frame特效数据
|
||||
int Delay; // 延迟
|
||||
};
|
||||
struct AniInfo
|
||||
{
|
||||
std::vector<std::string> Img_List; // img列表
|
||||
std::vector<AniFrame> Frame; // ani列表
|
||||
std::unordered_map<std::string, AniFlag> Flag; // ani特效数据
|
||||
};
|
||||
namespace AniScriptParser
|
||||
{
|
||||
static std::string Get_Ani_Flag(int data)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
return "LOOP";
|
||||
case 1:
|
||||
return "SHADOW";
|
||||
case 3:
|
||||
return "COORD";
|
||||
case 7:
|
||||
return "IMAGE_RATE";
|
||||
case 8:
|
||||
return "IMAGE_ROTATE";
|
||||
case 9:
|
||||
return "RGBA";
|
||||
case 10:
|
||||
return "INTERPOLATION";
|
||||
case 11:
|
||||
return "GRAPHIC_EFFECT";
|
||||
case 12:
|
||||
return "DELAY";
|
||||
case 13:
|
||||
return "DAMAGE_TYPE";
|
||||
case 14:
|
||||
return "DAMAGE_BOX";
|
||||
case 15:
|
||||
return "ATTACK_BOX";
|
||||
case 16:
|
||||
return "PLAY_SOUND";
|
||||
case 17:
|
||||
return "PRELOAD";
|
||||
case 18:
|
||||
return "SPECTRUM";
|
||||
case 23:
|
||||
return "SET_FLAG";
|
||||
case 24:
|
||||
return "FLIP_TYPE";
|
||||
case 25:
|
||||
return "LOOP_START";
|
||||
case 26:
|
||||
return "LOOP_END";
|
||||
case 27:
|
||||
return "CLIP";
|
||||
case 28:
|
||||
return "OPERATION";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string Get_Ani_Effect_Type(int data)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
return "NONE";
|
||||
case 1:
|
||||
return "DODGE";
|
||||
case 2:
|
||||
return "LINEARDODGE";
|
||||
case 3:
|
||||
return "DARK";
|
||||
case 4:
|
||||
return "XOR";
|
||||
case 5:
|
||||
return "MONOCHROME";
|
||||
case 6:
|
||||
return "SPACEDISTORT";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
static std::string Get_Ani_Flip_Type(int data)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case 1:
|
||||
return "HORIZON";
|
||||
case 2:
|
||||
return "VERTICAL";
|
||||
case 3:
|
||||
return "ALL";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
static std::string Get_Ani_Damage_Type(int data)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
return "NORMAL";
|
||||
case 1:
|
||||
return "SUPERARMOR";
|
||||
case 2:
|
||||
return "UNBREAKABLE";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
#include "AssetManager.h"
|
||||
#include "EngineCore/Asset_Script.h"
|
||||
#include "Tool/Blob.hpp"
|
||||
#include "Tool/Tool_String.hpp"
|
||||
|
||||
AssetManager::AssetManager()
|
||||
{
|
||||
}
|
||||
AssetManager::~AssetManager()
|
||||
{
|
||||
}
|
||||
|
||||
AniInfo AssetManager::StructAniInfo(std::string path)
|
||||
{
|
||||
AniInfo Info;
|
||||
std::vector<BYTE> Data = Asset_Script::GetInstance().GetFileContentByte(path);
|
||||
Blob blob(Data);
|
||||
|
||||
int Frame_Max = blob.getUShort();
|
||||
int Img_Count = blob.getUShort();
|
||||
|
||||
printf("Frame_Max : %d\n", Frame_Max);
|
||||
printf("Img_Count : %d\n", Img_Count);
|
||||
|
||||
// Img的路径读取 存入数组
|
||||
for (int i = 0; i < Img_Count; i++)
|
||||
{
|
||||
int Buf = blob.getInt();
|
||||
std::string ImgPath = blob.getString(Buf);
|
||||
printf("ImgPath : %s\n", ImgPath.c_str());
|
||||
Info.Img_List.push_back(ImgPath);
|
||||
}
|
||||
|
||||
// Ani头部标签数量
|
||||
int Ani_H_Item_Count = blob.getUShort();
|
||||
// 处理标签
|
||||
for (int i = 0; i < Ani_H_Item_Count; i++)
|
||||
{
|
||||
int Type = blob.getUShort();
|
||||
switch (Type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
std::string Key = AniScriptParser::Get_Ani_Flag(Type);
|
||||
int Value = blob.getByte();
|
||||
Info.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
case 28:
|
||||
{
|
||||
std::string Key = AniScriptParser::Get_Ani_Flag(Type);
|
||||
int Value = blob.getUShort();
|
||||
Info.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
{
|
||||
blob.getByte();
|
||||
blob.getInt();
|
||||
blob.getInt();
|
||||
blob.getInt();
|
||||
blob.get256();
|
||||
blob.get256();
|
||||
blob.get256();
|
||||
blob.get256();
|
||||
blob.getUShort();
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 读取每一个Img
|
||||
for (int i = 0; i < Frame_Max; i++)
|
||||
{
|
||||
AniFrame FrameObject;
|
||||
|
||||
// 碰撞框项目数量
|
||||
int Ani_Box_Item_Count = blob.getUShort();
|
||||
for (int j = 0; j < Ani_Box_Item_Count; j++)
|
||||
{
|
||||
int Box_Type = blob.getUShort();
|
||||
std::vector<int> D_Box_b;
|
||||
for (int k = 0; k < 6; k++)
|
||||
{
|
||||
D_Box_b.push_back(blob.getInt());
|
||||
}
|
||||
if (Box_Type == 15)
|
||||
FrameObject.AttackBox.push_back(D_Box_b);
|
||||
else
|
||||
FrameObject.DamageBox.push_back(D_Box_b);
|
||||
}
|
||||
|
||||
// 调用的第几个Img
|
||||
int Index_Buf = blob.getShort();
|
||||
if (Index_Buf != -1)
|
||||
{
|
||||
FrameObject.Img_Path = Tool_toLowerCase(Info.Img_List[Index_Buf]);
|
||||
FrameObject.Img_Index = blob.getUShort();
|
||||
}
|
||||
else
|
||||
{
|
||||
FrameObject.Img_Path = "";
|
||||
FrameObject.Img_Index = 0;
|
||||
}
|
||||
|
||||
// 坐标
|
||||
FrameObject.Img_Pos = SDL_Point{blob.getInt(), blob.getInt()};
|
||||
|
||||
// Img中的项目数量
|
||||
int Img_Flag_Count = blob.getUShort();
|
||||
for (int j = 0; j < Img_Flag_Count; j++)
|
||||
{
|
||||
int Img_Flag_Type = blob.getUShort();
|
||||
std::string Key;
|
||||
int Value;
|
||||
switch (Img_Flag_Type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 10:
|
||||
{
|
||||
Key = AniScriptParser::Get_Ani_Flag(Img_Flag_Type);
|
||||
Value = blob.getInt();
|
||||
FrameObject.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
Key = "COORD";
|
||||
Value = blob.getUShort();
|
||||
FrameObject.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
{
|
||||
Key = "PRELOAD";
|
||||
Value = 1;
|
||||
FrameObject.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
Key = "IMAGE_RATE";
|
||||
SDL_FPoint pos{
|
||||
blob.getFloat(),
|
||||
blob.getFloat()};
|
||||
FrameObject.Flag.emplace(Key, pos);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
Key = "IMAGE_ROTATE";
|
||||
Value = blob.getFloat();
|
||||
FrameObject.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
Key = "RGBA";
|
||||
std::vector<float> RGBA = {
|
||||
blob.get256(),
|
||||
blob.get256(),
|
||||
blob.get256(),
|
||||
blob.get256()};
|
||||
FrameObject.Flag.emplace(Key, RGBA);
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
{
|
||||
int Effect_Type = blob.getUShort();
|
||||
Key = "GRAPHIC_EFFECT_" + AniScriptParser::Get_Ani_Effect_Type(Effect_Type);
|
||||
std::vector<float> effect;
|
||||
switch (Effect_Type)
|
||||
{
|
||||
case 5:
|
||||
{
|
||||
effect.push_back(blob.get256());
|
||||
effect.push_back(blob.get256());
|
||||
effect.push_back(blob.get256());
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
effect.push_back(blob.get256());
|
||||
effect.push_back(blob.get256());
|
||||
break;
|
||||
}
|
||||
}
|
||||
FrameObject.Flag.emplace(Key, effect);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
{
|
||||
Value = blob.getInt();
|
||||
FrameObject.Delay = Value;
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
{
|
||||
Key = "DAMAGE_TYPE";
|
||||
std::string DTYPE = AniScriptParser::Get_Ani_Damage_Type(blob.getUShort());
|
||||
FrameObject.Flag.emplace(Key, DTYPE);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
int SoundTempSize = blob.getInt();
|
||||
Key = "PLAY_SOUND";
|
||||
std::string sound = blob.getString(SoundTempSize);
|
||||
FrameObject.Flag.emplace(Key, sound);
|
||||
break;
|
||||
}
|
||||
case 23:
|
||||
{
|
||||
Key = "SET_FLAG";
|
||||
Value = blob.getInt();
|
||||
FrameObject.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 24:
|
||||
{
|
||||
Key = "FLIP_TYPE";
|
||||
std::string FTYPEValue = AniScriptParser::Get_Ani_Flip_Type(blob.getUShort());
|
||||
FrameObject.Flag.emplace(Key, FTYPEValue);
|
||||
break;
|
||||
}
|
||||
case 25:
|
||||
{
|
||||
Key = "LOOP_START";
|
||||
FrameObject.Flag.emplace(Key, 1);
|
||||
break;
|
||||
}
|
||||
case 26:
|
||||
{
|
||||
Key = "LOOP_END";
|
||||
Value = blob.getInt();
|
||||
FrameObject.Flag.emplace(Key, Value);
|
||||
break;
|
||||
}
|
||||
case 27:
|
||||
{
|
||||
Key = "CLIP";
|
||||
std::vector<int> ClipArr{
|
||||
blob.getShort(),
|
||||
blob.getShort(),
|
||||
blob.getShort(),
|
||||
blob.getShort(),
|
||||
};
|
||||
FrameObject.Flag.emplace(Key, ClipArr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Info.Frame.push_back(FrameObject);
|
||||
}
|
||||
|
||||
return Info;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include "Asset/AnimationStruct.h" //Ani结构
|
||||
|
||||
class AssetManager
|
||||
{
|
||||
|
||||
public:
|
||||
AssetManager(const AssetManager &) = delete;
|
||||
AssetManager &operator=(const AssetManager &) = delete;
|
||||
AssetManager(AssetManager &&) = delete;
|
||||
AssetManager &operator=(AssetManager &&) = delete;
|
||||
// 全局访问点
|
||||
static AssetManager &GetInstance()
|
||||
{
|
||||
static AssetManager instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
AssetManager(/* args */);
|
||||
~AssetManager();
|
||||
|
||||
public:
|
||||
// 构造Ani结构体
|
||||
AniInfo StructAniInfo(std::string path);
|
||||
};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#include "Global_Game.h"
|
||||
|
||||
Global_Game::Global_Game()
|
||||
{
|
||||
}
|
||||
Global_Game::~Global_Game()
|
||||
{
|
||||
}
|
||||
|
||||
void Global_Game::Init()
|
||||
{
|
||||
// 初始化ttf字体资源
|
||||
TTF_Font *FontBuf = TTF_OpenFont("Fonts/LXGWWenKai-Regular.ttf", 24);
|
||||
// TTF_Font *FontBuf = TTF_OpenFont("Fonts/Gothica-Book.ttf", 24);
|
||||
// TTF_Font *FontBuf = TTF_OpenFont("Fonts/Gasinamu.ttf", 24);
|
||||
if (!FontBuf)
|
||||
{
|
||||
SDL_LogError(0, "字体加载失败: %s", TTF_GetError());
|
||||
}
|
||||
Fonts.push_back(FontBuf);
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include "EngineCore/Game.h"
|
||||
|
||||
class Global_Game
|
||||
{
|
||||
public:
|
||||
Global_Game(const Global_Game &) = delete;
|
||||
Global_Game &operator=(const Global_Game &) = delete;
|
||||
Global_Game(Global_Game &&) = delete;
|
||||
Global_Game &operator=(Global_Game &&) = delete;
|
||||
// 全局访问点
|
||||
static Global_Game &GetInstance()
|
||||
{
|
||||
static Global_Game instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Init();
|
||||
|
||||
public:
|
||||
// 当前游戏状态 0未初始化
|
||||
int game_state = 0;
|
||||
|
||||
public:
|
||||
// 字体资源
|
||||
std::vector<TTF_Font *> Fonts;
|
||||
|
||||
private:
|
||||
Global_Game(/* args */);
|
||||
~Global_Game();
|
||||
};
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
#include "Scene/Scene_Loading_UI.h"
|
||||
#include "Scene/Scene_SelectCharacter_UI.hpp"
|
||||
#include "Scene/Scene_Test.h"
|
||||
#include "Scene_Loading_UI.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
#include "EngineFrame/Component/Text.h"
|
||||
#include "Global/Global_Game.h"
|
||||
#include "EngineCore/Asset_Script.h"
|
||||
|
||||
Scene_Loading_UI::Scene_Loading_UI(/* args */)
|
||||
{
|
||||
}
|
||||
|
||||
Scene_Loading_UI::~Scene_Loading_UI()
|
||||
{
|
||||
}
|
||||
|
||||
void Scene_Loading_UI::Enter()
|
||||
{
|
||||
// 加载OGG文件
|
||||
music = Mix_LoadMUS("Music/characterSelectStage.ogg");
|
||||
if (music)
|
||||
{
|
||||
Mix_PlayMusic(music, 1);
|
||||
}
|
||||
|
||||
RefPtr<Actor> actor = new Actor;
|
||||
AddChild(actor);
|
||||
|
||||
RefPtr<Sprite> BackGroundSp = new Sprite("sprite/interface2/nowloading/nowloading.img", 1);
|
||||
actor->AddComponent(BackGroundSp);
|
||||
RefPtr<Sprite> BackGround2Sp = new Sprite("sprite/interface2/nowloading/nowloading.img", 0);
|
||||
BackGround2Sp->SetPos(SDL_Point{0, 686});
|
||||
actor->AddComponent(BackGround2Sp);
|
||||
RefPtr<Sprite> LoadCircleSp = new Sprite("sprite/interface2/nowloading/nowloading.img", 4);
|
||||
LoadCircleSp->SetName("LoadCircle");
|
||||
LoadCircleSp->SetPos(SDL_Point{1280 - 60, 686 - 60});
|
||||
LoadCircleSp->SetBlendMode(SDL_BLENDMODE_ADD);
|
||||
LoadCircleSp->SetAnchor(SDL_FPoint{0.5, 0.5});
|
||||
actor->AddComponent(LoadCircleSp);
|
||||
|
||||
actor->SetCallbackOnUpdate([LoadCircleSp](float deltaTime) mutable
|
||||
{
|
||||
float angle = LoadCircleSp->GetAngle();
|
||||
LoadCircleSp->SetAngle(angle + 180.0f * deltaTime); });
|
||||
|
||||
// 文字测试
|
||||
// RefPtr<Text> text = new Text("测试文字加载中...", Global_Game::GetInstance().Fonts[0], SDL_Color{255, 255, 255, 255}, SDL_Color{0, 0, 0, 255}, 4);
|
||||
// actor->AddComponent(text);
|
||||
}
|
||||
|
||||
void Scene_Loading_UI::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Scene_Loading_UI::Update(float deltaTime)
|
||||
{
|
||||
Scene::Update(deltaTime);
|
||||
if (Asset_Script::GetInstance().InitFlag)
|
||||
{
|
||||
// 设定游戏层场景
|
||||
RefPtr<Scene_Test> scene = new Scene_Test;
|
||||
Game::GetInstance().ChangeScene(scene);
|
||||
// 设定UI层场景
|
||||
RefPtr<Scene_SelectCharacter_UI> sceneUI = new Scene_SelectCharacter_UI;
|
||||
Game::GetInstance().ChangeUIScene(sceneUI);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene_Loading_UI::Render(float deltaTime)
|
||||
{
|
||||
Scene::Render(deltaTime);
|
||||
}
|
||||
|
||||
void Scene_Loading_UI::Exit()
|
||||
{
|
||||
if (music)
|
||||
{
|
||||
Mix_FreeMusic(music);
|
||||
music = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
#include <SDL2/SDL_mixer.h>
|
||||
|
||||
class Scene_Loading_UI : public Scene
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
Scene_Loading_UI(/* args */);
|
||||
~Scene_Loading_UI();
|
||||
|
||||
public:
|
||||
void Enter() override;
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render(float deltaTime) override;
|
||||
void Exit() override;
|
||||
|
||||
//加载界面音乐
|
||||
Mix_Music *music = nullptr;
|
||||
};
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
#include "Asset/AssetManager.h"
|
||||
|
||||
class Scene_SelectCharacter_UI : public Scene
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
Scene_SelectCharacter_UI(/* args */) {
|
||||
|
||||
};
|
||||
~Scene_SelectCharacter_UI() {
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
void Enter() override
|
||||
{
|
||||
AssetManager::GetInstance().StructAniInfo("common/training/main/main.ani");
|
||||
SDL_Log("进入了选择角色场景!");
|
||||
};
|
||||
// void HandleEvents(SDL_Event *e) override;
|
||||
// void Update(float deltaTime) override;
|
||||
// void Render(float deltaTime) override;
|
||||
// void Exit() override;
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#include "Scene_Test.h"
|
||||
#include <memory>
|
||||
#include <EngineCore/Game.h>
|
||||
Scene_Test::Scene_Test()
|
||||
{
|
||||
}
|
||||
|
||||
Scene_Test::~Scene_Test()
|
||||
{
|
||||
SDL_Log("Scene_Test::我的ID是%d --- 我被释放了!", this->MyId);
|
||||
}
|
||||
|
||||
void Scene_Test::Enter()
|
||||
{
|
||||
SDL_Log("进入测试场景!");
|
||||
}
|
||||
|
||||
void Scene_Test::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Scene_Test::Update(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Scene_Test::Render(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Scene_Test::Exit()
|
||||
{
|
||||
SDL_Log("Scene_Test::退出测试场景!当前引用计数%d", this->GetRefCount());
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
|
||||
class Scene_Test : public Scene
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
Scene_Test(/* args */);
|
||||
~Scene_Test();
|
||||
|
||||
public:
|
||||
void Enter() override;
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render(float deltaTime) override;
|
||||
void Exit() override;
|
||||
|
||||
public:
|
||||
int MyId = 0;
|
||||
};
|
||||
Loading…
Reference in New Issue