Compare commits
18 Commits
f8a05026d5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 39b100acff | |||
| 239425c47d | |||
| 60596f2772 | |||
| 648386cd73 | |||
| 56994b3927 | |||
| 8c0623b397 | |||
| dab9990b44 | |||
| fc1078f20c | |||
| 580e7cf72b | |||
| 367ac0bab7 | |||
| 4ae803b4f2 | |||
| 541f89b0b2 | |||
| c89243452d | |||
| bccdc3d231 | |||
| 917322934d | |||
| 1e04c04600 | |||
| ddde270ad5 | |||
| e0d7329905 |
93
.emmyrc.json
93
.emmyrc.json
@ -1,93 +0,0 @@
|
||||
{
|
||||
"completion": {
|
||||
"enable": true,
|
||||
"autoRequire": true,
|
||||
"autoRequireFunction": "require",
|
||||
"autoRequireNamingConvention": "keep",
|
||||
"autoRequireSeparator": ".",
|
||||
"callSnippet": false,
|
||||
"postfix": "@",
|
||||
"baseFunctionIncludesName": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"disable": [
|
||||
"unnecessary-if"
|
||||
],
|
||||
"enable": true,
|
||||
"globals": [],
|
||||
"globalsRegex": [],
|
||||
"severity": {},
|
||||
"enables": [],
|
||||
"diagnosticInterval": 500
|
||||
},
|
||||
"signature": {
|
||||
"detailSignatureHelper": true
|
||||
},
|
||||
"hint": {
|
||||
"enable": true,
|
||||
"paramHint": true,
|
||||
"indexHint": true,
|
||||
"localHint": true,
|
||||
"overrideHint": true,
|
||||
"metaCallHint": true
|
||||
},
|
||||
"runtime": {
|
||||
"version": "LuaLatest",
|
||||
"requireLikeFunction": [],
|
||||
"frameworkVersions": [],
|
||||
"extensions": [],
|
||||
"requirePattern": [],
|
||||
"classDefaultCall": {
|
||||
"functionName": "",
|
||||
"forceNonColon": false,
|
||||
"forceReturnSelf": false
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"ignoreDir": [],
|
||||
"ignoreGlobs": [],
|
||||
"library": [],
|
||||
"workspaceRoots": [],
|
||||
"preloadFileSize": 0,
|
||||
"encoding": "utf-8",
|
||||
"moduleMap": [],
|
||||
"reindexDuration": 5000,
|
||||
"enableReindex": false
|
||||
},
|
||||
"resource": {
|
||||
"paths": []
|
||||
},
|
||||
"codeLens": {
|
||||
"enable": true
|
||||
},
|
||||
"strict": {
|
||||
"requirePath": false,
|
||||
"typeCall": false,
|
||||
"arrayIndex": true,
|
||||
"metaOverrideFileDefine": true,
|
||||
"docBaseConstMatchBaseType": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"enable": true
|
||||
},
|
||||
"references": {
|
||||
"enable": true,
|
||||
"fuzzySearch": true,
|
||||
"shortStringSearch": false
|
||||
},
|
||||
"hover": {
|
||||
"enable": true
|
||||
},
|
||||
"documentColor": {
|
||||
"enable": true
|
||||
},
|
||||
"codeAction": {
|
||||
"insertSpace": false
|
||||
},
|
||||
"inlineValues": {
|
||||
"enable": true
|
||||
},
|
||||
"doc": {
|
||||
"privateName": []
|
||||
}
|
||||
}
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@ -76,3 +76,16 @@ Plugins/**/Intermediate/*
|
||||
# Cache files for the editor to use
|
||||
DerivedDataCache/*
|
||||
|
||||
BusyRabbit.uproject.DotSettings.user
|
||||
|
||||
Plugins/SpinePlugin/Script/SpinePlugin.Glue
|
||||
Script/ManagedBusyRabbit/bin
|
||||
Script/ManagedBusyRabbit/obj
|
||||
Script/ManagedBusyRabbit/Properties
|
||||
Script/BusyRabbit.Glue/bin
|
||||
Script/BusyRabbit.Glue/BusyRabbit
|
||||
Script/BusyRabbit.Glue/obj
|
||||
Script/BusyRabbit.Glue/Properties
|
||||
Script/BusyRabbit.Glue/AssetIds.cs
|
||||
Script/BusyRabbit.Glue/GameplayTags.cs
|
||||
Script/BusyRabbit.Glue/TraceChannel.cs
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"FileVersion": 3,
|
||||
"EngineAssociation": "5.4",
|
||||
"EngineAssociation": "5.6",
|
||||
"Category": "",
|
||||
"Description": "",
|
||||
"Modules": [
|
||||
@ -9,9 +9,7 @@
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "Default",
|
||||
"AdditionalDependencies": [
|
||||
"slua_unreal",
|
||||
"Engine",
|
||||
"PaperZD",
|
||||
"CoreUObject",
|
||||
"GameplayAbilities",
|
||||
"UMG"
|
||||
@ -26,11 +24,6 @@
|
||||
"Editor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "PaperZD",
|
||||
"Enabled": true,
|
||||
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/c4b43502026047d89296cd7bffd92828"
|
||||
},
|
||||
{
|
||||
"Name": "GameplayAbilities",
|
||||
"Enabled": true
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=4F8A2207_002DE0F5_002DA9C1_002D5E41_002D4243D0FAAC15_002Fd_003Aboost_002D1_005F82_005F0_002Fd_003Ainclude_002Fd_003Aboost_002Fd_003Acoroutine_002Fd_003Adetail_002Ff_003Apreallocated_002Ehpp/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=4F8A2207_002DE0F5_002DA9C1_002D5E41_002D4243D0FAAC15_002Fd_003Aboost_002D1_005F82_005F0_002Fd_003Ainclude_002Fd_003Aboost_002Fd_003Asafe_005Fnumerics_002Fd_003Aconcept_002Ff_003Apromotion_005Fpolicy_002Ehpp/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=5E061600_002DD0A1_002DF678_002DBF8E_002D1D2CD7670646_002Fd_003AEigen_002Fd_003Asrc_002Fd_003ACore_002Fd_003Autil_002Ff_003AConstants_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=B5255153_002DA839_002D6956_002D3EF8_002D0716EE76F13A_002Fd_003A5414_002Fd_003AInclude_002Fd_003Atools_002Fd_003Aclang_002Fd_003Arewrite_005Fto_005Fchrome_005Fstyle_002Fd_003Atests_002Fd_003Agen_002Ff_003Athing_002Eh/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
@ -15,8 +15,8 @@ ManualIPAddress=
|
||||
[/Script/EngineSettings.GameMapsSettings]
|
||||
GlobalDefaultGameMode=/Game/Blueprint/Bp_BusyGameMode.Bp_BusyGameMode_C
|
||||
GameInstanceClass=/Script/BusyRabbit.BusyGameInstance
|
||||
EditorStartupMap=/Game/Level/HomeLand.HomeLand
|
||||
GameDefaultMap=/Game/Level/HomeLand.HomeLand
|
||||
EditorStartupMap=/Game/Level/FalconPlain.FalconPlain
|
||||
GameDefaultMap=/Game/Level/FalconPlain.FalconPlain
|
||||
|
||||
[/Script/Engine.RendererSettings]
|
||||
r.Mobile.AntiAliasing=0
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
;METADATA=(Diff=true, UseCommands=true)
|
||||
[/Script/GameplayTags.GameplayTagsSettings]
|
||||
ImportTagsFromConfig=True
|
||||
WarnOnInvalidTags=True
|
||||
@ -5,14 +6,35 @@ ClearInvalidTags=False
|
||||
AllowEditorTagUnloading=True
|
||||
AllowGameTagUnloading=False
|
||||
FastReplication=False
|
||||
bDynamicReplication=False
|
||||
InvalidTagCharacters="\"\',"
|
||||
NumBitsForContainerSize=6
|
||||
NetIndexFirstBitSegment=16
|
||||
+GameplayTagList=(Tag="Ability.Block.UltimatePlaying",DevComment="大招正在释放中")
|
||||
+GameplayTagList=(Tag="Ability.Common",DevComment="通用技能")
|
||||
+GameplayTagList=(Tag="Ability.Common.Move",DevComment="移动技能")
|
||||
+GameplayTagList=(Tag="Ability.Flags.Cooldown",DevComment="技能冷却")
|
||||
+GameplayTagList=(Tag="Ability.Flags.Recast",DevComment="可以再次释放技能的标记")
|
||||
+GameplayTagList=(Tag="Ability.Fox",DevComment="狐狸技能标签")
|
||||
+GameplayTagList=(Tag="Ability.Fox.CastTag",DevComment="可以释放技能的标签")
|
||||
+GameplayTagList=(Tag="Ability.Fox.CastTag.Ultimate1",DevComment="可以使用大招第一阶段")
|
||||
+GameplayTagList=(Tag="Ability.Fox.CastTag.Ultimate2",DevComment="可以使用二阶大招")
|
||||
+GameplayTagList=(Tag="Ability.Fox.CastTag.Ultimate3",DevComment="可以使用第三阶段大招")
|
||||
+GameplayTagList=(Tag="Ability.Fox.StateTag",DevComment="状态标签")
|
||||
+GameplayTagList=(Tag="Ability.Fox.StateTag.Ultimate1",DevComment="正在使用第一阶段大招")
|
||||
+GameplayTagList=(Tag="Ability.Fox.StateTag.Ultimate2",DevComment="正在使用第二阶段大招")
|
||||
+GameplayTagList=(Tag="Ability.Fox.StateTag.Ultimate3",DevComment="正在使用第三阶段大招")
|
||||
+GameplayTagList=(Tag="Ability.Fox.UltimateStage1",DevComment="一阶大招")
|
||||
+GameplayTagList=(Tag="Ability.Fox.UltimateStage2",DevComment="二阶大招就绪标签")
|
||||
+GameplayTagList=(Tag="Ability.Fox.UltimateStage3",DevComment="三阶大招就绪")
|
||||
+GameplayTagList=(Tag="Ability.Recast",DevComment="技能可重新释放标签")
|
||||
+GameplayTagList=(Tag="Ability.Recast.Ultimate",DevComment="大招可重新释放")
|
||||
+GameplayTagList=(Tag="Ability.Role.AttributeConsume",DevComment="角色属性损耗debuff")
|
||||
+GameplayTagList=(Tag="Ability.Role.EatFood",DevComment="干饭")
|
||||
+GameplayTagList=(Tag="Ability.Role.Pick",DevComment="角色采集物品")
|
||||
+GameplayTagList=(Tag="Ability.Role.Recover",DevComment="角色状态恢复技能")
|
||||
+GameplayTagList=(Tag="Ability.Role.Roll",DevComment="角色无敌翻滚")
|
||||
+GameplayTagList=(Tag="Ability.Role.Ultimate",DevComment="角色大招")
|
||||
+GameplayTagList=(Tag="Buff.Indispersible.HungerConsume",DevComment="饥饿值消耗,不可被驱散")
|
||||
+GameplayTagList=(Tag="Buff.RoleConsume.Health",DevComment="角色因饥饿掉血的debuff")
|
||||
+GameplayTagList=(Tag="Buff.RoleConsume.Hunger",DevComment="角色每秒钟的饥饿消耗")
|
||||
@ -25,6 +47,8 @@ NetIndexFirstBitSegment=16
|
||||
+GameplayTagList=(Tag="CookProcess.Diced",DevComment="切丁")
|
||||
+GameplayTagList=(Tag="CookProcess.Mashed",DevComment="切泥")
|
||||
+GameplayTagList=(Tag="CookProcess.Sliced",DevComment="切片操作")
|
||||
+GameplayTagList=(Tag="Effect.Duration",DevComment="效果的持续时长")
|
||||
+GameplayTagList=(Tag="Effect.Factor",DevComment="效果的乘法系数")
|
||||
+GameplayTagList=(Tag="GameItem.Building",DevComment="建筑物")
|
||||
+GameplayTagList=(Tag="GameItem.Food",DevComment="游戏内的可食用物品")
|
||||
+GameplayTagList=(Tag="Ingredient",DevComment="烹饪食材")
|
||||
@ -34,6 +58,9 @@ NetIndexFirstBitSegment=16
|
||||
+GameplayTagList=(Tag="Ingredient.Vegetable.Carrot",DevComment="胡萝卜")
|
||||
+GameplayTagList=(Tag="Recover.Role.Health",DevComment="回复生命值")
|
||||
+GameplayTagList=(Tag="Recover.Role.Hunger",DevComment="恢复饥饿值")
|
||||
+GameplayTagList=(Tag="Resource",DevComment="资源")
|
||||
+GameplayTagList=(Tag="Resource.Building",DevComment="建筑物")
|
||||
+GameplayTagList=(Tag="Resource.Building.Campsite",DevComment="营地")
|
||||
+GameplayTagList=(Tag="Status.Role.Invincible",DevComment="不掉血标签")
|
||||
+GameplayTagList=(Tag="Terrain.Desert",DevComment="荒漠地形")
|
||||
+GameplayTagList=(Tag="Terrain.Forest",DevComment="森林")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Data/Ability/FoxUltimateDataAsset.uasset
Normal file
BIN
Content/Data/Ability/FoxUltimateDataAsset.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Data/Level/LevelResourceConfig.uasset
Normal file
BIN
Content/Data/Level/LevelResourceConfig.uasset
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/Gas/Ability/Role/Common/GA_MoveAbility.uasset
Normal file
BIN
Content/Gas/Ability/Role/Common/GA_MoveAbility.uasset
Normal file
Binary file not shown.
BIN
Content/Gas/Ability/Role/Fox/GA_FoxUltimate.uasset
Normal file
BIN
Content/Gas/Ability/Role/Fox/GA_FoxUltimate.uasset
Normal file
Binary file not shown.
BIN
Content/Gas/Effects/Calc/MMC_FoxUltimateCostCalc.uasset
Normal file
BIN
Content/Gas/Effects/Calc/MMC_FoxUltimateCostCalc.uasset
Normal file
Binary file not shown.
BIN
Content/Gas/Effects/Role/Fox/GE_Accelerate.uasset
Normal file
BIN
Content/Gas/Effects/Role/Fox/GE_Accelerate.uasset
Normal file
Binary file not shown.
BIN
Content/Gas/Effects/Role/Fox/GE_FoxUltimateCost.uasset
Normal file
BIN
Content/Gas/Effects/Role/Fox/GE_FoxUltimateCost.uasset
Normal file
Binary file not shown.
BIN
Content/Gas/Effects/Role/Fox/GE_UltimateCooldown.uasset
Normal file
BIN
Content/Gas/Effects/Role/Fox/GE_UltimateCooldown.uasset
Normal file
Binary file not shown.
BIN
Content/Gas/Effects/Role/Fox/GE_UltimateRecast.uasset
Normal file
BIN
Content/Gas/Effects/Role/Fox/GE_UltimateRecast.uasset
Normal file
Binary file not shown.
Binary file not shown.
@ -1,38 +0,0 @@
|
||||
---@enum EBusyRoleState
|
||||
local EBusyRoleState = {
|
||||
BonfireIdle = 0,
|
||||
Searching = 1,
|
||||
Picking = 2,
|
||||
PickFinished = 3,
|
||||
BackBonfire = 4
|
||||
}
|
||||
|
||||
---@enum ERoleMoveDirection
|
||||
local ERoleMoveDirection = {
|
||||
Move_Right = 0,
|
||||
Move_Left = 1,
|
||||
Move_All_Cnt = 2
|
||||
};
|
||||
|
||||
---@enum EBusyItemEffectType
|
||||
local EBusyItemEffectType = {
|
||||
Health = 0,
|
||||
Hunger = 1,
|
||||
Speed = 2,
|
||||
};
|
||||
|
||||
---@enum EBusyAnimationPhase
|
||||
local EBusyAnimationPhase = {
|
||||
PrepareCast = 0,
|
||||
Casting = 1,
|
||||
PostCast = 2,
|
||||
};
|
||||
|
||||
---@enum EWidgetLayoutType
|
||||
local EWidgetLayoutType = {
|
||||
MainLayer = 0,
|
||||
PopupLayer = 1,
|
||||
FloatLayer = 2,
|
||||
TopLayer = 3,
|
||||
LayerTypeMax = 4
|
||||
};
|
||||
@ -1,3 +0,0 @@
|
||||
--- @class BusyGameplayLibrary
|
||||
--- @field K2_GetWorld fun(obj:table):table
|
||||
local BusyGameplayLibrary = {}
|
||||
@ -1,35 +0,0 @@
|
||||
-- 这个返回值固定返回的是string,我希望当我使用import("ERoleState")时,它返回的是ERoleState的注解,或者是ERoleState.lua这个文件返回值的注解
|
||||
-- ---自定义导入函数,功能类似require但支持额外特性
|
||||
-- ---@generic T
|
||||
-- ---@param modulePath T 模块路径或预加载的模块
|
||||
-- ---@param hotReload? boolean 是否启用热重载
|
||||
-- ---@return T 返回加载的模块
|
||||
-- function import(modulePath, hotReload) end
|
||||
|
||||
|
||||
---自定义模块导入函数,支持类型感知的模块加载
|
||||
---@generic T : string -- 限定modulePath为字符串类型
|
||||
---@param modulePath `T` 模块路径(如"ERoleState")
|
||||
---@param hotReload? boolean 是否启用热重载
|
||||
---@return T 返回对应模块的类型
|
||||
---@error 当模块加载失败时抛出错误
|
||||
function import(modulePath, hotReload) end
|
||||
|
||||
|
||||
function Class(a, b, c) end
|
||||
|
||||
---@class slua
|
||||
slua = {
|
||||
createDelegate = function(func) end
|
||||
}
|
||||
|
||||
--- @class KismetSystemLibrary
|
||||
KismetSystemLibrary = {
|
||||
K2_ClearTimerHandle = function() end
|
||||
}
|
||||
|
||||
|
||||
--- @class GameplayStatics
|
||||
--- @field GetPlayerController fun(uobj:table,idx:number):table
|
||||
--- @field GetGameState fun(uobj:table):table
|
||||
local GameplayStatics
|
||||
@ -1,8 +0,0 @@
|
||||
---@enum ESlateVisibility
|
||||
local ESlateVisibility = {
|
||||
Visible = 0,
|
||||
Collapsed = 1,
|
||||
Hidden = 2,
|
||||
HitTestInvisible = 3,
|
||||
SelfHitTestInvisible = 4
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,222 +0,0 @@
|
||||
#ifndef LIBPDEBUG_H
|
||||
#define LIBPDEBUG_H
|
||||
|
||||
//1.使用源码编译,要打开宏USE_SOURCE_CODE. win下要设置LUA_INTEGER和lua版本号
|
||||
#define LUA_DEBUGGER_NAME "LuaPanda" //debugger's name in LuaDebug.lua
|
||||
#define HOOK_LIB_VERSION "3.2.0" //lib version
|
||||
//#define USE_SOURCE_CODE //using source code to build
|
||||
#if !defined(USE_SOURCE_CODE) && defined(_WIN32)
|
||||
#define LUA_INTEGER long long //set LUA_INTEGER. In 501 is ptrdiff_t. 503 can set longlong(64bit) or int(32bit)
|
||||
#define LUA_VERSION_NUM 503 //lua version used by WIN32 build lib. eg. 501,503
|
||||
#endif
|
||||
//setting end
|
||||
|
||||
#if !defined(USE_SOURCE_CODE) && defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
#include <Tlhelp32.h>
|
||||
#else
|
||||
//2.如果lua源码是C++形式,注释掉下面extern "C"
|
||||
extern "C"{
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include "luaconf.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
//3.如果lua代码在命名空间中,要设置用户命名空间. 防止找不到lua方法
|
||||
//using namespace slua;
|
||||
|
||||
#ifdef USE_SOURCE_CODE
|
||||
extern "C" void pdebug_init(lua_State* L);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOURCE_CODE) && defined(_WIN32)
|
||||
/*
|
||||
** Lua - An Extensible Extension Language
|
||||
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
||||
** See Copyright Notice at the end of this file
|
||||
*/
|
||||
#if LUA_VERSION_NUM == 501
|
||||
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
|
||||
#endif
|
||||
|
||||
#define LUA_TNONE (-1)
|
||||
#define LUA_TNIL 0
|
||||
#define LUA_TBOOLEAN 1
|
||||
#define LUA_TLIGHTUSERDATA 2
|
||||
#define LUA_TNUMBER 3
|
||||
#define LUA_TSTRING 4
|
||||
#define LUA_TTABLE 5
|
||||
#define LUA_TFUNCTION 6
|
||||
#define LUA_TUSERDATA 7
|
||||
#define LUA_TTHREAD 8
|
||||
#define LUA_NUMBER double
|
||||
#define LUA_REGISTRYINDEX (-10000)
|
||||
#define LUA_ENVIRONINDEX (-10001)
|
||||
#define LUA_GLOBALSINDEX (-10002)
|
||||
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
|
||||
#define LUA_IDSIZE 60
|
||||
#define LUA_HOOKCALL 0
|
||||
#define LUA_HOOKRET 1
|
||||
#define LUA_HOOKLINE 2
|
||||
#define LUA_HOOKCOUNT 3
|
||||
#define LUA_HOOKTAILRET 4
|
||||
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
|
||||
#define LUA_MASKRET (1 << LUA_HOOKRET)
|
||||
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
|
||||
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
|
||||
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
|
||||
#define lua_pop(L,n) lua_settop(L, -(n)-1)
|
||||
#define lua_newtable(L) lua_createtable(L, 0, 0)
|
||||
|
||||
struct lua_State;
|
||||
struct lua_Debug {
|
||||
int event;
|
||||
const char *name; /* (n) */
|
||||
const char *namewhat; /* (n) `global', `local', `field', `method' */
|
||||
const char *what; /* (S) `Lua', `C', `main', `tail' */
|
||||
const char *source; /* (S) */
|
||||
int currentline; /* (l) */
|
||||
int nups; /* (u) number of upvalues */
|
||||
int linedefined; /* (S) */
|
||||
int lastlinedefined; /* (S) */
|
||||
char short_src[LUA_IDSIZE]; /* (S) */
|
||||
/* private part */
|
||||
int i_ci; /* active function */
|
||||
};
|
||||
|
||||
typedef LUA_INTEGER lua_Integer;
|
||||
typedef LUA_NUMBER lua_Number;
|
||||
typedef int (*lua_CFunction) (lua_State *L);
|
||||
typedef struct luaL_Reg {
|
||||
const char *name;
|
||||
lua_CFunction func;
|
||||
} luaL_Reg;
|
||||
|
||||
#define LUA_KCONTEXT ptrdiff_t
|
||||
typedef LUA_KCONTEXT lua_KContext;
|
||||
|
||||
//lua function
|
||||
typedef lua_Integer(*luaDLL_checkinteger) (lua_State *L, int numArg);
|
||||
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
||||
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
|
||||
typedef const lua_Number *(*luaDLL_version)(lua_State *L);
|
||||
typedef void (*luaLDLL_register)(lua_State *L, const char *libname, const luaL_Reg *l);
|
||||
typedef int (*luaDLL_gettop)(lua_State *L);
|
||||
typedef const char *(*luaDLL_pushstring)(lua_State *L, const char *s);
|
||||
typedef int (*luaDLL_settop)(lua_State *L, int idx);
|
||||
typedef int (*luaDLL_tointeger)(lua_State *L, int idx);
|
||||
typedef int (*luaDLL_next)(lua_State *L, int idx);
|
||||
typedef int (*luaDLL_pcall)(lua_State *L, int nargs, int nresults, int errfunc);
|
||||
typedef void (*luaDLL_pushnil)(lua_State *L);
|
||||
typedef void (*luaDLL_getfield)(lua_State *L, int idx, const char *k);
|
||||
typedef int (*luaDLL_getinfo)(lua_State *L, const char *what, void *ar);
|
||||
typedef void (*luaDLL_pushinteger) (lua_State *L, lua_Integer n);
|
||||
#if LUA_VERSION_NUM == 501
|
||||
typedef int(*luaDLL_sethook)(lua_State *L, void* func, int mask, int count);
|
||||
#else
|
||||
typedef void (*luaDLL_sethook)(lua_State *L, lua_Hook f, int mask, int count);
|
||||
#endif
|
||||
typedef void (*luaDLL_pushnumber)(lua_State *L, lua_Number n);
|
||||
typedef lua_Number (*luaDLL_checknumber)(lua_State *L, int narg);
|
||||
typedef const char *(*luaDLL_checklstring)(lua_State *L, int narg, size_t *len);
|
||||
typedef const char *(*luaDLL_tolstring)(lua_State *L, int idx, size_t *len);
|
||||
typedef int (*luaDLL_type)(lua_State *L, int idx);
|
||||
//5.3
|
||||
typedef void (*luaDLL_createtable)(lua_State *L, int narray, int nrec);
|
||||
typedef void (*luaDLL_setfuncs)(lua_State *L, const luaL_Reg *l, int nup);
|
||||
typedef lua_Integer(*luaDLL_tointegerx)(lua_State *L, int idx, int *pisnum);
|
||||
typedef int (*luaDLL_getglobal)(lua_State *L, const char *name);
|
||||
typedef int (*luaDLL_pcallk)(lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k);
|
||||
typedef int (*luaDLL_toboolean)(lua_State *L, int index);
|
||||
|
||||
luaDLL_checkinteger luaL_checkinteger;
|
||||
luaDLL_version lua_version;
|
||||
luaDLL_gettop lua_gettop;
|
||||
luaDLL_pushstring lua_pushstring;
|
||||
luaLDLL_register luaL_register;
|
||||
luaDLL_settop lua_settop;
|
||||
luaDLL_pcall lua_pcall;
|
||||
luaDLL_pushnumber lua_pushnumber;
|
||||
luaDLL_checklstring luaL_checklstring;
|
||||
luaDLL_tointeger lua_tointeger;
|
||||
luaDLL_pushnil lua_pushnil;
|
||||
luaDLL_getfield lua_getfield;
|
||||
luaDLL_next lua_next;
|
||||
luaDLL_getinfo lua_getinfo;
|
||||
luaDLL_sethook lua_sethook;
|
||||
luaDLL_checknumber luaL_checknumber;
|
||||
luaDLL_type lua_type;
|
||||
luaDLL_tolstring lua_tolstring;
|
||||
luaDLL_pushinteger lua_pushinteger;
|
||||
luaDLL_toboolean lua_toboolean;
|
||||
//
|
||||
HMODULE hInstLibrary;
|
||||
|
||||
//slua-ue header
|
||||
#if LUA_VERSION_NUM > 501
|
||||
//5.3
|
||||
luaDLL_createtable lua_createtable;
|
||||
luaDLL_setfuncs luaL_setfuncs;
|
||||
luaDLL_tointegerx lua_tointegerx;
|
||||
luaDLL_getglobal lua_getglobal;
|
||||
luaDLL_pcallk lua_pcallk;
|
||||
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
|
||||
#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL);
|
||||
|
||||
#define PURE_API =0
|
||||
namespace slua {
|
||||
struct LuaInterface {
|
||||
virtual const lua_Number *lua_version(lua_State *L) PURE_API;
|
||||
virtual const char *lua_pushstring(lua_State *L, const char *s) PURE_API;
|
||||
virtual int lua_gettop(lua_State *L) PURE_API;
|
||||
virtual void lua_settop(lua_State *L, int index) PURE_API;
|
||||
virtual int lua_pcallk(lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k) PURE_API;
|
||||
virtual void lua_pushnumber(lua_State *L, lua_Number n) PURE_API;
|
||||
virtual const char *luaL_checklstring(lua_State *L, int arg, size_t *l) PURE_API;
|
||||
virtual const char *lua_tolstring(lua_State *L, int index, size_t *len) PURE_API;
|
||||
virtual int lua_type(lua_State *L, int index) PURE_API;
|
||||
virtual lua_Integer lua_tointegerx(lua_State *L, int index, int *isnum) PURE_API;
|
||||
virtual void lua_pushnil(lua_State *L) PURE_API;
|
||||
virtual int lua_getfield(lua_State *L, int index, const char *k) PURE_API;
|
||||
virtual int lua_next(lua_State *L, int index) PURE_API;
|
||||
virtual int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) PURE_API;
|
||||
virtual void lua_sethook(lua_State *L, lua_Hook f, int mask, int count) PURE_API;
|
||||
virtual lua_Number luaL_checknumber(lua_State *L, int arg) PURE_API;
|
||||
virtual void lua_createtable(lua_State *L, int narr, int nrec) PURE_API;
|
||||
virtual void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) PURE_API;
|
||||
virtual int lua_getglobal(lua_State *L, const char *name) PURE_API;
|
||||
virtual int lua_toboolean(lua_State *L, int index) PURE_API;
|
||||
};
|
||||
}
|
||||
typedef slua::LuaInterface* (*dll_GetLuaInterface)();
|
||||
dll_GetLuaInterface getInter;
|
||||
#endif //LUA_VERSION_NUM > 501
|
||||
#endif //_WIN32
|
||||
#endif //LIBPDEBUG_H
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
@ -1,21 +0,0 @@
|
||||
local Bonfire = {}
|
||||
local GamePlayUtils = require("GamePlay.Utils")
|
||||
local Utils = require("GamePlay.Utils")
|
||||
|
||||
local item_effect_health_tag = "Change.Role.Health"
|
||||
local item_effect_hunger_tag = "Change.Role.Health"
|
||||
|
||||
|
||||
function Bonfire:ctor()
|
||||
end
|
||||
|
||||
function Bonfire:ReceiveBeginPlay()
|
||||
self.Inventory:SetInventoryCapacity(20)
|
||||
end
|
||||
|
||||
function Bonfire:StoreItem(item_id)
|
||||
return self.Inventory:DepositItems(item_id, 1)
|
||||
end
|
||||
|
||||
|
||||
return Class(nil, nil, Bonfire)
|
||||
@ -1,108 +0,0 @@
|
||||
-- 禁用不必要的if诊断警告
|
||||
---@diagnostic disable: unnecessary-if
|
||||
|
||||
-- 导入基类模块
|
||||
local PWClass = require("Core.PWClass")
|
||||
|
||||
--- @class StorageClass
|
||||
--- @field max_capacity number 最大容量(格子总数)
|
||||
--- @field cur_capacity number 当前已用容量
|
||||
--- @field grids_list table[] 存储格子列表
|
||||
local StorageClass = PWClass.derive("StorageClass")
|
||||
|
||||
--- 创建新物品格子
|
||||
--- @param item_id any 物品唯一标识
|
||||
--- @return table 新创建的物品格子
|
||||
local function CreateGrid(item_id)
|
||||
return {
|
||||
item_id = item_id, -- 物品ID
|
||||
cur_cnt = 0, -- 当前数量
|
||||
max_cnt = 1 -- 最大堆叠数(可扩展为配置项)
|
||||
}
|
||||
end
|
||||
|
||||
--- 查找或创建可用物品格子
|
||||
--- @param storage StorageClass 存储实例
|
||||
--- @param item_id any 目标物品ID
|
||||
--- @return table 可用格子(找不到时创建新格子)
|
||||
local function FindOrCreateAvailableGrid(storage, item_id)
|
||||
-- 优先查找同类型且未满的格子
|
||||
for _, grid in ipairs(storage.grids_list) do
|
||||
if grid.item_id == item_id and grid.cur_cnt < grid.max_cnt then
|
||||
return grid
|
||||
end
|
||||
end
|
||||
|
||||
-- 无可用格子时创建新的物品类型格子
|
||||
local new_grid = CreateGrid(item_id)
|
||||
table.insert(storage.grids_list, new_grid)
|
||||
return new_grid
|
||||
end
|
||||
|
||||
--- 构造函数
|
||||
function StorageClass:ctor()
|
||||
self.max_capacity = 10 -- 默认最大容量
|
||||
self.cur_capacity = 0 -- 当前使用容量
|
||||
self.grids_list = {} -- 格子容器
|
||||
end
|
||||
|
||||
--- 设置存储容量上限
|
||||
--- @param capacity number 新的最大容量
|
||||
function StorageClass:SetMaxCapacity(capacity)
|
||||
self.max_capacity = capacity
|
||||
end
|
||||
|
||||
--- 存储物品
|
||||
--- @param item_id any 要存储的物品ID
|
||||
function StorageClass:Store(item_id)
|
||||
-- 容量检查
|
||||
if self.cur_capacity >= self.max_capacity then
|
||||
return false -- 建议返回操作结果
|
||||
end
|
||||
|
||||
local grid = FindOrCreateAvailableGrid(self, item_id)
|
||||
grid.cur_cnt = grid.cur_cnt + 1
|
||||
self.cur_capacity = self.cur_capacity + 1
|
||||
return true -- 建议添加返回值
|
||||
end
|
||||
|
||||
--- 取出物品
|
||||
--- @param item_id any 目标物品ID
|
||||
--- @return boolean 是否成功取出
|
||||
function StorageClass:Withdraw(item_id)
|
||||
-- 逆序遍历提高取出效率(通常新物品在末尾)
|
||||
for i = #self.grids_list, 1, -1 do
|
||||
local grid = self.grids_list[i]
|
||||
if grid ~= nil and grid.item_id == item_id and grid.cur_cnt > 0 then
|
||||
grid.cur_cnt = grid.cur_cnt - 1
|
||||
self.cur_capacity = self.cur_capacity - 1
|
||||
|
||||
-- 清空空格子
|
||||
if grid.cur_cnt == 0 then
|
||||
table.remove(self.grids_list, i)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function StorageClass:Visit(vistor)
|
||||
for _, grid in ipairs(self.grids_list) do vistor(_, grid) end
|
||||
end
|
||||
|
||||
--- 查询物品(满足条件的物品及数量)
|
||||
--- @param query_function fun(item_id:any):boolean 物品过滤函数
|
||||
--- @return table 物品ID到数量的映射表
|
||||
function StorageClass:QueryItem(query_function)
|
||||
local items = {}
|
||||
for _, grid in ipairs(self.grids_list) do
|
||||
-- 仅统计有物品且满足查询条件的格子
|
||||
if grid.cur_cnt > 0 and query_function(grid.item_id) then
|
||||
items[grid.item_id] = (items[grid.item_id] or 0) + grid.cur_cnt
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
return StorageClass
|
||||
@ -1,18 +0,0 @@
|
||||
local PlayerState = {}
|
||||
|
||||
function PlayerState:ctor()
|
||||
|
||||
|
||||
end
|
||||
|
||||
function PlayerState:ReceiveBeginPlay()
|
||||
print(self, "PlayerState:ReceiveBeginPlay")
|
||||
end
|
||||
|
||||
function PlayerState:ReceiveEndPlay()
|
||||
print(self, "PlayerState:ReceiveEndPlay")
|
||||
end
|
||||
|
||||
|
||||
|
||||
return Class(nil, nil, PlayerState)
|
||||
@ -1,112 +0,0 @@
|
||||
local FVector = import "Vector"
|
||||
local Vector2D = require("Utils.Vector2D")
|
||||
local Library = import "BusyGamePlayLibrary"
|
||||
local GameplayStatics = import("GameplayStatics")
|
||||
|
||||
local SubSystem = {}
|
||||
|
||||
local function GetNearestBonfire(system, x, y)
|
||||
local selected_bonfire = nil
|
||||
local selected_distance = nil
|
||||
|
||||
for _, bonfire in ipairs(system.bonfire_list) do
|
||||
local pos = bonfire:K2_GetActorLocation()
|
||||
local distance = (x - pos.X) ^ 2 + (y - pos.Y) ^ 2
|
||||
if selected_distance == nil or distance < selected_distance then
|
||||
selected_distance = distance
|
||||
selected_bonfire = bonfire
|
||||
end
|
||||
end
|
||||
return selected_bonfire
|
||||
end
|
||||
|
||||
function SubSystem:ctor()
|
||||
self.current_role = nil
|
||||
self.bonfire_list = {} -- 所有的篝火列表
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveSubSystemInitialize()
|
||||
self.current_role = nil
|
||||
self.bonfire_list = {}
|
||||
end
|
||||
|
||||
function SubSystem:GetNearestBonfire()
|
||||
if self.current_role then
|
||||
local cur_pos = self.current_role:K2_GetActorLocation()
|
||||
return GetNearestBonfire(self, cur_pos.X, cur_pos.Y)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function SubSystem:SpawnBonfire(position)
|
||||
local pos = FVector()
|
||||
local world = self:K2_GetWorld()
|
||||
local cls = Library.GetGameClass("Bonfire")
|
||||
pos.X, pos.Y, pos.Z = position.X, position.Y, 20
|
||||
local bonfire = world:SpawnActor(cls, pos, nil, nil)
|
||||
table.insert(self.bonfire_list, bonfire)
|
||||
return bonfire
|
||||
end
|
||||
|
||||
function SubSystem:SpawnRole(bonfire)
|
||||
local role_pos = FVector()
|
||||
local world = self:K2_GetWorld()
|
||||
local pos = bonfire:K2_GetActorLocation()
|
||||
local cls = Library.GetGameClass("BusyRole")
|
||||
role_pos.X, role_pos.Y, role_pos.Z = pos.X, pos.Y, pos.Z + 10
|
||||
self.current_role = world:SpawnActor(cls, role_pos, nil, nil)
|
||||
if self.current_role ~= nil then
|
||||
self.current_role:SetRole("Rabbit")
|
||||
return self.current_role
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function SubSystem:SpawnLevelItem(item_id)
|
||||
-- 随机在角色周围生成
|
||||
|
||||
local distance = math.random(128, 500)
|
||||
local angle = (math.random(0, 360) / 360) * 2 * 3.14;
|
||||
|
||||
local world = self:K2_GetWorld()
|
||||
local item_position = FVector()
|
||||
local center = self.current_role:K2_GetActorLocation()
|
||||
local cls = import("BusyLevelItem")
|
||||
|
||||
item_position.Z = center.Z - 1
|
||||
item_position.X = center.X + math.cos(angle) * distance
|
||||
item_position.Y = center.Y + math.sin(angle) * distance
|
||||
|
||||
local item = world:SpawnActor(cls, item_position, nil, nil)
|
||||
item:SetLevelItemID(item_id)
|
||||
return center
|
||||
end
|
||||
|
||||
function SubSystem:SpawnLevelItemReward(level_item)
|
||||
assert(self.current_role ~= nil)
|
||||
|
||||
local world = self:K2_GetWorld()
|
||||
local cls = Library.GetGameClass("LevelItemReward")
|
||||
|
||||
local random_angle = (math.random() - 0.5) * (math.pi / 2)
|
||||
local direction = Vector2D.Normalize(self.current_role:GetMoveDirection())
|
||||
|
||||
local sin, cos = math.sin(random_angle), math.cos(random_angle)
|
||||
|
||||
-- 应用旋转矩阵
|
||||
direction.X = direction.X * cos - direction.Y * sin
|
||||
direction.Y = direction.X * sin + direction.Y * cos
|
||||
|
||||
local item_location = level_item:K2_GetActorLocation()
|
||||
|
||||
local reward_location = Vector2D.Add(item_location, Vector2D.Mul(direction, 200))
|
||||
|
||||
local item = world:SpawnActor(cls,
|
||||
Vector2D.ToUnrealEngine3D(reward_location, item_location.Z),
|
||||
nil, nil
|
||||
)
|
||||
return item
|
||||
end
|
||||
|
||||
return Class(nil, nil, SubSystem)
|
||||
@ -1,119 +0,0 @@
|
||||
---@class ItemGenerator 物品生成器类
|
||||
local ItemGenerator = {
|
||||
item_data = {},
|
||||
period = 100,
|
||||
item_distributions = {}
|
||||
}
|
||||
ItemGenerator.__index = ItemGenerator
|
||||
|
||||
---数组洗牌函数(Fisher-Yates算法)
|
||||
---@param array any[] 需要打乱顺序的数组
|
||||
local function ShuffleArray(array)
|
||||
for i = #array, 2, -1 do -- 从后往前遍历
|
||||
local j = math.random(i) -- 生成1到i的随机数
|
||||
array[i], array[j] = array[j], array[i] -- 交换元素位置
|
||||
end
|
||||
end
|
||||
|
||||
---创建物品生成器实例
|
||||
---@param period number 生成周期次数
|
||||
---@param item_data table<number, number> 物品配置表 {物品ID = 总生成数量}
|
||||
---@return ItemGenerator 物品生成器实例
|
||||
local function CreateItemGenerator(period, item_data)
|
||||
local self = setmetatable({}, ItemGenerator)
|
||||
---@type number 存储生成周期
|
||||
self.period = period
|
||||
---@type table<number, number> 原始配置数据
|
||||
self.item_data = item_data
|
||||
---@type number 当前调用次数
|
||||
self.current_call = 0
|
||||
---@type table<number, number[]> 物品分布数据结构
|
||||
self.item_distributions = {}
|
||||
self:InitializeDistributions()
|
||||
return self
|
||||
end
|
||||
|
||||
---初始化物品分布数据
|
||||
function ItemGenerator:InitializeDistributions()
|
||||
-- 遍历所有物品配置
|
||||
for item_id, total in pairs(self.item_data) do
|
||||
-- 计算基础值和余数(保证总数 = 基础值*period + 余数)
|
||||
local base = math.floor(total / self.period)
|
||||
local remainder = total % self.period
|
||||
|
||||
-- 创建初始分布数组(全部填充基础值)
|
||||
local distribution = {}
|
||||
for i = 1, self.period do
|
||||
distribution[i] = base
|
||||
end
|
||||
|
||||
-- 生成索引数组并洗牌(用于随机分配余数)
|
||||
local indices = {}
|
||||
for i = 1, self.period do
|
||||
indices[i] = i
|
||||
end
|
||||
ShuffleArray(indices) -- 打乱索引顺序
|
||||
|
||||
-- 将余数随机分配到前remainder个位置
|
||||
for i = 1, remainder do
|
||||
distribution[indices[i]] = distribution[indices[i]] + 1
|
||||
end
|
||||
|
||||
-- 存储当前物品的分布数组
|
||||
self.item_distributions[item_id] = distribution
|
||||
end
|
||||
end
|
||||
|
||||
---重置生成器状态(当调用次数超过N时触发)
|
||||
function ItemGenerator:Reinitialize()
|
||||
self:InitializeDistributions() -- 重新生成分布数据
|
||||
self.current_call = 0 -- 重置调用计数器
|
||||
end
|
||||
|
||||
---生成物品列表(每次调用产生一个周期的结果)
|
||||
---@return number[] 包含物品ID的数组(结果经过随机排序)
|
||||
function ItemGenerator:Generate()
|
||||
-- 当超过周期次数时重置状态
|
||||
if self.current_call >= self.period then
|
||||
self:Reinitialize()
|
||||
end
|
||||
|
||||
local current_step = self.current_call + 1 -- 获取当前步骤(1-based)
|
||||
local result = {} -- 结果收集器
|
||||
|
||||
-- 遍历所有物品的分布数据
|
||||
for item_id, distribution in pairs(self.item_distributions) do
|
||||
local count = distribution[current_step] -- 获取当前步骤应生成数量
|
||||
for _ = 1, count do
|
||||
table.insert(result, item_id) -- 按数量添加物品ID到结果集
|
||||
end
|
||||
end
|
||||
|
||||
ShuffleArray(result) -- 打乱结果顺序保证随机性
|
||||
self.current_call = self.current_call + 1 -- 增加调用计数器
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
---获取当前未生成的物品剩余数量
|
||||
---@return table<number, number> 返回物品ID和剩余数量的映射表
|
||||
function ItemGenerator:GetRemainingItems()
|
||||
local remaining = {}
|
||||
local current_step = self.current_call -- 注意这里使用已调用次数(0-based)
|
||||
|
||||
-- 遍历所有物品的分布数据
|
||||
for item_id, distribution in pairs(self.item_distributions) do
|
||||
local total_remaining = 0
|
||||
|
||||
-- 计算从下一个步骤到周期结束的总数量
|
||||
for step = current_step + 1, self.period do
|
||||
total_remaining = total_remaining + distribution[step]
|
||||
end
|
||||
|
||||
remaining[item_id] = total_remaining
|
||||
end
|
||||
|
||||
return remaining
|
||||
end
|
||||
|
||||
return CreateItemGenerator
|
||||
@ -1,73 +0,0 @@
|
||||
local SubSystem = {}
|
||||
local Reactive = require("Core.Reactive")
|
||||
local Library = import("BusyGamePlayLibrary")
|
||||
local GameplayStatics = import("GameplayStatics")
|
||||
local BusyGamePlayLibrary = import("BusyGamePlayLibrary")
|
||||
|
||||
|
||||
local function CreateItemGenerator(level_config_data)
|
||||
local Generator = require("GamePlay.Level.BusyLevelItemGenerator")
|
||||
|
||||
local item_data = {}
|
||||
local period = level_config_data.Period
|
||||
for k, v in pairs(level_config_data.LevelItemIds) do
|
||||
item_data[k] = v.CountOfPeriod
|
||||
end
|
||||
return Generator(period, item_data)
|
||||
end
|
||||
|
||||
function SubSystem:Bp_ShouldCreateSubsystem(world)
|
||||
return false
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveSubSystemInitialize()
|
||||
local world = BusyGamePlayLibrary.K2_GetWorld(self)
|
||||
self.start_time = GameplayStatics.GetTimeSeconds(world)
|
||||
|
||||
self.proxy = Reactive.ReactiveProperty({
|
||||
current_seconds = 0
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveWorldBeginPlay()
|
||||
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self)
|
||||
|
||||
-- 读取关卡配置
|
||||
local is_suc, row_data = Library.GetLevelBaseConfig("Default", nil)
|
||||
assert(is_suc == true, "Can't find level base config")
|
||||
self.level_base_config = row_data
|
||||
|
||||
-- 创建物品生成器
|
||||
self.generator = CreateItemGenerator(row_data)
|
||||
|
||||
-- 创建初始篝火
|
||||
-- local bonfire = BusyActorManagerSubSystem:SpawnBonfire(row_data.FirstBonfirePosition)
|
||||
|
||||
-- 创建角色
|
||||
-- local role = BusyActorManagerSubSystem:SpawnRole(bonfire)
|
||||
-- GameplayStatics.GetPlayerController(self, 0):Possess(role)
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveSubSystemTick(DeltaTime)
|
||||
-- local proxy = self.proxy
|
||||
-- local world = BusyGamePlayLibrary.K2_GetWorld(self)
|
||||
-- local current_time = GameplayStatics.GetTimeSeconds(world)
|
||||
-- local escapse_time = math.floor(current_time - self.start_time)
|
||||
-- if escapse_time > proxy.current_seconds then
|
||||
-- self:TrySpawnLevelItem()
|
||||
-- proxy.current_seconds = escapse_time
|
||||
-- print(proxy.current_seconds)
|
||||
-- end
|
||||
end
|
||||
|
||||
function SubSystem:TrySpawnLevelItem()
|
||||
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self)
|
||||
local items = self.generator:Generate()
|
||||
for i, item_id in pairs(items) do
|
||||
BusyActorManagerSubSystem:SpawnLevelItem(item_id)
|
||||
print(i, item_id)
|
||||
end
|
||||
end
|
||||
|
||||
return Class(nil, nil, SubSystem)
|
||||
@ -1,103 +0,0 @@
|
||||
--- @class BusyLevelItem
|
||||
local LevelItem = {}
|
||||
local Reactive = require("Core.Reactive")
|
||||
local RoleUtils = require("GamePlay.Utils.RoleUtils")
|
||||
local GameplayUtils = require("GamePlay.Utils")
|
||||
local KismetSystemLibrary = import("KismetSystemLibrary")
|
||||
|
||||
function LevelItem:ReceiveBeginPlay()
|
||||
self:SetLevelItemID(self.CurrentItemID)
|
||||
self.world = self:GetWorld()
|
||||
print("LevelItem:ReceiveBeginPlay")
|
||||
end
|
||||
|
||||
|
||||
function LevelItem:TempSetting()
|
||||
self:ReceiveBeginPlay()
|
||||
end
|
||||
|
||||
function LevelItem:ReceiveLevelItemSetted(Config)
|
||||
self.config = Config
|
||||
self.PickBar.Widget:BindLevelItem(self)
|
||||
|
||||
print("LevelItem:ReceiveLevelItemSetted", KismetSystemLibrary.IsValid(self))
|
||||
|
||||
|
||||
self.attribute_watcher = Reactive.Watcher(function()
|
||||
if self.LuaLevelItemAttribute.Health <= 0 then
|
||||
self:GenerateDropItems()
|
||||
local location = self:K2_GetActorLocation()
|
||||
location.Z = -1000
|
||||
self:K2_SetActorLocation(location, false, nil, false)
|
||||
self:SetLifeSpan(0.3)
|
||||
self.attribute_watcher:Destroy()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
function LevelItem:GenerateDropItems()
|
||||
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self.world)
|
||||
local role = RoleUtils.GetRole(self)
|
||||
local role_location = role:K2_GetActorLocation()
|
||||
local curr_location = self:K2_GetActorLocation()
|
||||
|
||||
local collection_config = GameplayUtils.GetItemConfigByID(self.CurrentItemID)
|
||||
|
||||
local generated_dict = {}
|
||||
for _, config in pairs(collection_config.DropConfigs) do
|
||||
local base = 0
|
||||
local seed = math.random()
|
||||
for _, rate in pairs(config.configs) do
|
||||
local min = base
|
||||
local max = base + rate.Rate
|
||||
if seed >= min and seed < max then
|
||||
generated_dict[config.ItemID] = rate.Count
|
||||
break
|
||||
end
|
||||
base = max
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for item_id, count in pairs(generated_dict) do
|
||||
for _ = 1, count do
|
||||
local reward = BusyActorManagerSubSystem:SpawnLevelItemReward(self)
|
||||
|
||||
reward.Movement.speed = 300.0
|
||||
reward.Movement.accelerate = 600.0
|
||||
reward.Movement.direction = {
|
||||
X = curr_location.X - role_location.X,
|
||||
Y = curr_location.Y - role_location.Y
|
||||
}
|
||||
reward:SetRewardID(item_id)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- 接口
|
||||
function LevelItem:GetPickProcess()
|
||||
local process = self.LuaLevelItemAttribute.Health / self.config.PickTimeCost
|
||||
print("current process", process)
|
||||
return process
|
||||
end
|
||||
|
||||
|
||||
function LevelItem:GetPickCost()
|
||||
return self.LevelItemConfig.PickHungerCost
|
||||
end
|
||||
|
||||
function LevelItem:IsAlive()
|
||||
return self.LuaLevelItemAttribute.Health > 0
|
||||
end
|
||||
|
||||
function LevelItem:GetItemID()
|
||||
return self.CurrentItemID
|
||||
end
|
||||
|
||||
|
||||
return Class(nil, nil, LevelItem)
|
||||
@ -1,24 +0,0 @@
|
||||
local PlayerController = {}
|
||||
local KismetSystemLibrary = import("KismetSystemLibrary")
|
||||
|
||||
|
||||
|
||||
function PlayerController:convertCursorToWorldPosition()
|
||||
-- 将当前鼠标的位置转化为世界的位置
|
||||
local FVector = import("Vector")
|
||||
local WorldOrigin, WorldDirection = FVector(), FVector()
|
||||
local _, MouseX, MouseY = self:GetMousePosition(nil, nil)
|
||||
if self:DeprojectScreenPositionToWorld(
|
||||
MouseX, MouseY, WorldOrigin, WorldDirection
|
||||
)then
|
||||
return WorldOrigin.X, WorldOrigin.Y
|
||||
else
|
||||
return nil, nil
|
||||
end
|
||||
end
|
||||
|
||||
function PlayerController:QuitGame()
|
||||
KismetSystemLibrary.QuitGame(self, self, 0, false)
|
||||
end
|
||||
|
||||
return Class(nil, nil, PlayerController)
|
||||
@ -1,203 +0,0 @@
|
||||
local UIUtils = require("UI.Utils")
|
||||
local Reactive = require("Core.Reactive")
|
||||
local ERoleState = import("EBusyRoleState")
|
||||
local EBusyItemEffectType = import("EBusyItemEffectType")
|
||||
local GameplayStatics = import ("GameplayStatics")
|
||||
local GetGameplayTag = require("GamePlay.Utils").GetGameplayTag
|
||||
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
|
||||
local GamePlayUtils = require("GamePlay.Utils")
|
||||
local KismetMathLibrary = import("KismetMathLibrary")
|
||||
|
||||
local LevelItemRewardClass = import("LevelItemReward")
|
||||
|
||||
--- @class BusyRole
|
||||
local Role={
|
||||
movement_watcher = nil,
|
||||
interacte_item = nil
|
||||
}
|
||||
|
||||
local PickAbilityTag = "Ability.Role.Pick"
|
||||
local RecoverAbilityTag = "Ability.Role.Recover"
|
||||
local ConsumeAbilityTag = "Ability.Role.AttributeConsume"
|
||||
local RollAbilityTag = "Ability.Role.Roll"
|
||||
|
||||
-- 私有函数
|
||||
|
||||
-- 采集相关
|
||||
|
||||
--- @param role BusyRole
|
||||
--- @param pick_targer BusyLevelItem
|
||||
local function ResetPickWatcher(role, pick_targer)
|
||||
if role.pick_watcher ~= nil then
|
||||
role.pick_watcher:Destroy()
|
||||
end
|
||||
role.pick_watcher = Reactive.Watcher(function()
|
||||
if not pick_targer:IsAlive() then
|
||||
role.pick_watcher:Destroy()
|
||||
role.pick_watcher = nil
|
||||
role.carried_item_id = pick_targer:GetItemID()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- 存储正在搬运的物品
|
||||
local function StoreCarriedItem(role)
|
||||
-- if not role.carried_item_id then return end
|
||||
-- local sub_system = BusyActorManagerSubSystem.Get(role)
|
||||
-- local bonfire = sub_system:GetNearestBonfire()
|
||||
-- if bonfire:StoreItem(role.carried_item_id) then
|
||||
-- role.carried_item_id = nil
|
||||
-- end
|
||||
end
|
||||
|
||||
function Role:ctor()
|
||||
self.pick_timer = nil
|
||||
self.carried_item_id = nil
|
||||
self.time_limited_tags = {}
|
||||
self.pick_watcher = nil -- 监听正在采集物品的状态
|
||||
self.proxy = Reactive.ReactiveProperty({
|
||||
state = ERoleState.BonfireIdle,
|
||||
is_alive = true,
|
||||
})
|
||||
end
|
||||
|
||||
function Role:ReceiveBeginPlay()
|
||||
self.bCanEverTick = false
|
||||
self.Inventory:DepositItems(200001, 2)
|
||||
self.movement_watcher = Reactive.Watcher(function()
|
||||
self:UpdateRoleState()
|
||||
end)
|
||||
end
|
||||
|
||||
function Role:ReceiveEndPlay()
|
||||
print(self, "Role:ReceiveEndPlay")
|
||||
|
||||
end
|
||||
|
||||
function Role:ReceiveSetRole(_)
|
||||
self:TryActiveAbility(ConsumeAbilityTag, nil)
|
||||
UIUtils.ShowWidget(self, "RoleState", {role=self})
|
||||
end
|
||||
|
||||
function Role:UpdateRoleState()
|
||||
-- 在auto run中访问Reactive Property的值,会导致多次调用,有性能隐患
|
||||
local role_state = Reactive.RawGet(self.proxy, "state")
|
||||
local move_proxy = self.Movement.proxy
|
||||
if move_proxy.isIdle then
|
||||
if role_state == ERoleState.Searching or role_state == ERoleState.PickFinished then
|
||||
self.proxy.state = ERoleState.BackBonfire
|
||||
self.Movement:BackBonfire()
|
||||
elseif role_state == ERoleState.BackBonfire then
|
||||
-- StoreCarriedItem(self)
|
||||
self.proxy.state = ERoleState.BonfireIdle
|
||||
end
|
||||
else
|
||||
if role_state == ERoleState.BonfireIdle then
|
||||
self.proxy.state = ERoleState.Searching
|
||||
end
|
||||
end
|
||||
print("old", role_state, "new", Reactive.RawGet(self.proxy, "state"), move_proxy.isIdle)
|
||||
end
|
||||
|
||||
function Role:StartPick(level_item)
|
||||
local GameplayEventData = import("GameplayEventData")
|
||||
local EventData = GameplayEventData()
|
||||
EventData.Instigator = self
|
||||
EventData.Target = level_item
|
||||
self.proxy.state = ERoleState.Picking
|
||||
self:TryActiveAbility(PickAbilityTag, EventData)
|
||||
-- ResetPickWatcher(self, level_item)
|
||||
end
|
||||
|
||||
function Role:OnTouch(_)
|
||||
local role_proxy = self.proxy
|
||||
if role_proxy.state == ERoleState.BonfireIdle then
|
||||
local pc = GameplayStatics.GetPlayerController(self:GetWorld(), 0)
|
||||
local world_x, world_y = pc:convertCursorToWorldPosition()
|
||||
role_proxy.state = ERoleState.Searching
|
||||
self.Movement:SetDestination(world_x, world_y)
|
||||
else
|
||||
print("nothing")
|
||||
end
|
||||
end
|
||||
|
||||
function Role:OnOverlapBegin(OverlappedComp, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult)
|
||||
if KismetMathLibrary.ClassIsChildOf(OtherActor:GetClass(), LevelItemRewardClass) then
|
||||
self.Inventory:DepositItems(OtherActor.RewardID, 1)
|
||||
OtherActor:ConditionalBeginDestroy()
|
||||
else
|
||||
if self.proxy.state ~= ERoleState.Searching then return end
|
||||
self.proxy.state = ERoleState.Picking
|
||||
self.Movement:Stop()
|
||||
self:StartPick(OtherActor)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- 使用翻滚技能
|
||||
function Role:UseRollSkill()
|
||||
self:TryActiveAbility(RollAbilityTag, nil)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- 接口
|
||||
function Role:GetPickEffect()
|
||||
return self.RoleConfig.PickEffect
|
||||
end
|
||||
|
||||
function Role:GetHealthPercent()
|
||||
local current_health = self.LuaRoleAttribute.Health or 0
|
||||
return current_health / self.RoleConfig.Health
|
||||
end
|
||||
|
||||
function Role:GetHungerPercent()
|
||||
return self.LuaRoleAttribute.Hunger / self.RoleConfig.Hunger
|
||||
end
|
||||
|
||||
function Role:GetHungerConsumeSpeed()
|
||||
if self.time_limited_tags["SkillRole"] ~= nil then
|
||||
return self.RoleConfig.HungerConsumeSpeed * 8
|
||||
else
|
||||
return self.RoleConfig.HungerConsumeSpeed
|
||||
end
|
||||
end
|
||||
|
||||
function Role:GetSpeed()
|
||||
return self.LuaRoleAttribute.MoveSpeed
|
||||
end
|
||||
|
||||
function Role:GetMoveDirection()
|
||||
return self.Movement.proxy.direction
|
||||
end
|
||||
|
||||
|
||||
--- 返回即将消耗的饥饿值和生命值
|
||||
function Role:CalcRealChangeByHunger(value)
|
||||
local config = self.RoleConfig
|
||||
local fixed_change, extra_health_need = 0, 0
|
||||
local cost_rate = config.HealthConsumeSpeed / config.HungerConsumeSpeed
|
||||
local remain_hunger = self.LuaRoleAttribute.Hunger + value
|
||||
if remain_hunger < 0 then
|
||||
fixed_change = remain_hunger
|
||||
extra_health_need = remain_hunger * cost_rate
|
||||
elseif remain_hunger > self.RoleConfig.Hunger then
|
||||
fixed_change = remain_hunger - self.RoleConfig.Hunger
|
||||
end
|
||||
return value - fixed_change, self:CalcRealChangeByHealth(extra_health_need)
|
||||
end
|
||||
|
||||
function Role:CalcRealChangeByHealth(value)
|
||||
if value == 0 then return 0 end
|
||||
local fixed_change = 0
|
||||
local remain_health = self.LuaRoleAttribute.Health + value
|
||||
if remain_health < 0 then
|
||||
fixed_change = remain_health
|
||||
elseif remain_health > self.RoleConfig.Health then
|
||||
fixed_change = remain_health - self.RoleConfig.Health
|
||||
end
|
||||
return value - fixed_change
|
||||
end
|
||||
|
||||
return Class(nil, nil, Role)
|
||||
@ -1,73 +0,0 @@
|
||||
local LevelFoxRole = {}
|
||||
local Vector2D = require("Utils.Vector2D")
|
||||
|
||||
function LevelFoxRole:ctor()
|
||||
|
||||
end
|
||||
|
||||
function LevelFoxRole:ReceiveBeginPlay()
|
||||
self["SpineAnimationComponent"]:SetAnimation(0, "Idle/Front", true)
|
||||
self.last_animation = "Idle/Front"
|
||||
end
|
||||
|
||||
|
||||
function LevelFoxRole:OnMoveDirectionChanged(InDirection)
|
||||
-- 运动组件更新方向响应函数
|
||||
local cur_animation
|
||||
if Vector2D.Equals(InDirection, Vector2D.Zero) then -- Idle的情况
|
||||
local forward_direction = self["MovementComponent"]:GetForwardDirection()
|
||||
if(forward_direction.Y >= 0) then
|
||||
cur_animation = "Idle/Front"
|
||||
else
|
||||
cur_animation = "Idle/Back"
|
||||
end
|
||||
else
|
||||
if(InDirection.Y >= 0) then
|
||||
cur_animation = "Move/Front"
|
||||
else
|
||||
cur_animation = "Move/Back"
|
||||
end
|
||||
end
|
||||
if cur_animation ~= self.last_animation then
|
||||
self["SpineAnimationComponent"]:SetAnimation(0, cur_animation, true)
|
||||
self.last_animation = cur_animation
|
||||
end
|
||||
|
||||
self["SpineAnimationComponent"]:SetTimeScale(1.0)
|
||||
end
|
||||
|
||||
|
||||
function LevelFoxRole:OnMove(location)
|
||||
-- 控制器移动相应函数
|
||||
self["MovementComponent"]:MoveTo(location)
|
||||
end
|
||||
|
||||
function LevelFoxRole:OnUltimateSkill()
|
||||
print("LevelFoxRole:OnUltimateSkill")
|
||||
local sprint_distance = 600
|
||||
local sprint_speed_rate = 3.8
|
||||
|
||||
-- 获取角色朝向
|
||||
local forward_direction = self["MovementComponent"]:GetForwardDirection()
|
||||
|
||||
self["MovementComponent"]:SprintTo(sprint_distance, sprint_speed_rate)
|
||||
|
||||
|
||||
local anim_comp = self["SpineAnimationComponent"]
|
||||
if forward_direction.X >= 0 then
|
||||
anim_comp:SetAnimation(0, "Ultimate/Right/UltimateStage1", false)
|
||||
else
|
||||
anim_comp:SetAnimation(0, "Ultimate/Left/UltimateStage1", false)
|
||||
end
|
||||
local anim_entry = anim_comp:GetCurrent(0)
|
||||
|
||||
local anim_total_time = anim_entry:GetAnimationEnd()
|
||||
local sprint_time = sprint_distance / (self:GetSpeed() * sprint_speed_rate)
|
||||
|
||||
anim_comp:SetTimeScale(anim_total_time / sprint_time)
|
||||
|
||||
print("hahhh", anim_total_time, sprint_time)
|
||||
end
|
||||
|
||||
|
||||
return Class(nil, nil, LevelFoxRole)
|
||||
@ -1,36 +0,0 @@
|
||||
local LevelRabbitRole = {}
|
||||
|
||||
function LevelRabbitRole:ctor()
|
||||
self.last_animation = "back/move"
|
||||
end
|
||||
|
||||
function LevelRabbitRole:ReceiveBeginPlay()
|
||||
self["SpineAnimationComponent"]:SetSkin("back/move")
|
||||
self["SpineAnimationComponent"]:SetAnimation(0, "animation", true)
|
||||
end
|
||||
|
||||
|
||||
function LevelRabbitRole:OnMove(location)
|
||||
-- 控制器移动相应函数
|
||||
self["MovementComponent"]:MoveTo(location)
|
||||
end
|
||||
|
||||
|
||||
function LevelRabbitRole:OnMoveDirectionChanged(InDirection)
|
||||
-- 运动组件更新方向响应函数
|
||||
local cur_animation
|
||||
if(InDirection.Y >= 0) then
|
||||
cur_animation = "front/move"
|
||||
else
|
||||
cur_animation = "back/move"
|
||||
end
|
||||
print("LevelRabbitRole:OnMoveDirectionChanged", cur_animation)
|
||||
if cur_animation ~= self.last_animation then
|
||||
self["SpineAnimationComponent"]:SetSkin(cur_animation)
|
||||
self["SpineAnimationComponent"]:SetSlotsToSetupPose()
|
||||
self.last_animation = cur_animation
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return Class(nil, nil, LevelRabbitRole)
|
||||
@ -1,4 +0,0 @@
|
||||
local Campsite = {}
|
||||
|
||||
|
||||
return Class(nil, nil, Campsite)
|
||||
@ -1,45 +0,0 @@
|
||||
local Vector = import("Vector")
|
||||
local GameplayStatics = import("GameplayStatics")
|
||||
local BusyGameplayLibrary = import("BusyGameplayLibrary")
|
||||
|
||||
|
||||
--[[****************************私有函数区域******************************]]--
|
||||
|
||||
--- 生成资源点
|
||||
local function GenerateResourcePoint()
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- 保留到以后做联机内容时拓展
|
||||
--- @class LevelGameMode
|
||||
--- @field GameMapActorClass table
|
||||
local LevelGameMode = {}
|
||||
|
||||
function LevelGameMode:ctor()
|
||||
self.map_actor = nil
|
||||
end
|
||||
|
||||
function LevelGameMode:ReceiveBeginPlay()
|
||||
print("LevelGameMode:ReceiveBeginPlay", self.GameMapActorClass)
|
||||
local world = BusyGameplayLibrary.K2_GetWorld(self)
|
||||
local game_state = GameplayStatics.GetGameState(self) --- @type LevelGameState
|
||||
|
||||
if self.GameMapActorClass then
|
||||
local map_actor = world:SpawnActor(self.GameMapActorClass, Vector(), nil, nil)
|
||||
game_state:SetGameMapActor(map_actor)
|
||||
end
|
||||
end
|
||||
|
||||
-- function LevelGameMode:K2_PostLogin(new_player_controller)
|
||||
-- local new_player_state = new_player_controller.PlayerState
|
||||
-- local role = new_player_state:CreateRoleRoster(new_player_controller)
|
||||
-- local new_pos = FVector()
|
||||
-- new_pos.X = 500
|
||||
-- new_pos.Y = 500
|
||||
-- new_pos.Z = 50
|
||||
-- role:K2_SetActorLocation(new_pos, true, nil, false)
|
||||
-- new_player_controller:Possess(role)
|
||||
-- end
|
||||
|
||||
return Class(nil, nil, LevelGameMode)
|
||||
@ -1,9 +0,0 @@
|
||||
--- @class LevelGameState
|
||||
local LevelGameState = {}
|
||||
|
||||
function LevelGameState:SetGameMapActor(game_map_actor)
|
||||
self.GameMapActor = game_map_actor
|
||||
end
|
||||
|
||||
|
||||
return Class(nil, nil, LevelGameState)
|
||||
@ -1,12 +0,0 @@
|
||||
local GameplayStatics = import("GameplayStatics")
|
||||
|
||||
local LevelPlayerState = {}
|
||||
|
||||
function LevelPlayerState:ReceiveBeginPlay()
|
||||
local pc = GameplayStatics.GetPlayerController(self, 0)
|
||||
local role = self:CreateRoleRoster(pc)
|
||||
print("LevelPlayerState:ReceiveBeginPlay", role, self:HasAuthority())
|
||||
pc:Possess(role)
|
||||
end
|
||||
|
||||
return Class(nil, nil, LevelPlayerState)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/UI/BP_BusyRootWidget.uasset
Normal file
BIN
Content/UI/BP_BusyRootWidget.uasset
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/UI/Level/BP_BusyLevelHud.uasset
Normal file
BIN
Content/UI/Level/BP_BusyLevelHud.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/StateBar/WBP_HealthBar.uasset
Normal file
BIN
Content/UI/Level/StateBar/WBP_HealthBar.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/StateBar/WBP_RoleHead.uasset
Normal file
BIN
Content/UI/Level/StateBar/WBP_RoleHead.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/StateBar/WBP_SatietyBar.uasset
Normal file
BIN
Content/UI/Level/StateBar/WBP_SatietyBar.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/StateBar/WBP_StateBar.uasset
Normal file
BIN
Content/UI/Level/StateBar/WBP_StateBar.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/UIControllers/BP_RoleStateController.uasset
Normal file
BIN
Content/UI/Level/UIControllers/BP_RoleStateController.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/WBP_MainPanel.uasset
Normal file
BIN
Content/UI/Level/WBP_MainPanel.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/bar.uasset
Normal file
BIN
Content/UI/Level/bar.uasset
Normal file
Binary file not shown.
BIN
Content/UI/Level/bar2.uasset
Normal file
BIN
Content/UI/Level/bar2.uasset
Normal file
Binary file not shown.
Binary file not shown.
2
Plugins/UnrealSharp/.gitattributes
vendored
Normal file
2
Plugins/UnrealSharp/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
84
Plugins/UnrealSharp/.gitignore
vendored
Normal file
84
Plugins/UnrealSharp/.gitignore
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
# Visual Studio 2015 user specific files
|
||||
.vs/
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.ipa
|
||||
|
||||
# These project files can be generated by the engine
|
||||
*.xcodeproj
|
||||
*.xcworkspace
|
||||
*.suo
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.VC.db
|
||||
*.VC.opendb
|
||||
|
||||
# Precompiled Assets
|
||||
SourceArt/**/*.png
|
||||
SourceArt/**/*.tga
|
||||
|
||||
# Binary Files
|
||||
Binaries/*
|
||||
Plugins/*/Binaries/*
|
||||
|
||||
# Builds
|
||||
Build/*
|
||||
|
||||
# Whitelist PakBlacklist-<BuildConfiguration>.txt files
|
||||
!Build/*/
|
||||
Build/*/**
|
||||
!Build/*/PakBlacklist*.txt
|
||||
|
||||
# Don't ignore icon files in Build
|
||||
!Build/**/*.ico
|
||||
|
||||
# Built data for maps
|
||||
*_BuiltData.uasset
|
||||
|
||||
# Configuration files generated by the Editor
|
||||
Saved/*
|
||||
|
||||
# Compiled source files for the engine to use
|
||||
Intermediate/*
|
||||
Plugins/*/Intermediate/*
|
||||
|
||||
# Cache files for the editor to use
|
||||
DerivedDataCache/*
|
||||
|
||||
*.user
|
||||
|
||||
.idea/
|
||||
|
||||
bin/
|
||||
Generated/
|
||||
obj/
|
||||
|
||||
*.props
|
||||
!Directory.Packages.props
|
||||
117
Plugins/UnrealSharp/Config/Default.UnrealSharpTypes.json
Normal file
117
Plugins/UnrealSharp/Config/Default.UnrealSharpTypes.json
Normal file
@ -0,0 +1,117 @@
|
||||
{
|
||||
"Structs": {
|
||||
"CustomTypes": [
|
||||
"FInstancedStruct"
|
||||
],
|
||||
"BlittableTypes": [
|
||||
{
|
||||
"Name": "EStreamingSourcePriority"
|
||||
},
|
||||
{
|
||||
"Name": "ETriggerEvent"
|
||||
},
|
||||
{
|
||||
"Name": "FVector",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector"
|
||||
},
|
||||
{
|
||||
"Name": "FVector2D",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector2D"
|
||||
},
|
||||
{
|
||||
"Name": "FVector_NetQuantize",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector"
|
||||
},
|
||||
{
|
||||
"Name": "FVector_NetQuantize10",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector"
|
||||
},
|
||||
{
|
||||
"Name": "FVector_NetQuantize100",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector"
|
||||
},
|
||||
{
|
||||
"Name": "FVector_NetQuantizeNormal",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector"
|
||||
},
|
||||
{
|
||||
"Name": "FVector2f",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector2f"
|
||||
},
|
||||
{
|
||||
"Name": "FVector3f",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector3f"
|
||||
},
|
||||
{
|
||||
"Name": "FVector4f",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector4f"
|
||||
},
|
||||
{
|
||||
"Name": "FQuatf4",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FVector4f"
|
||||
},
|
||||
{
|
||||
"Name": "FRotator",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FRotator"
|
||||
},
|
||||
{
|
||||
"Name": "FMatrix44f",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FMatrix44f"
|
||||
},
|
||||
{
|
||||
"Name": "FTransform",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FTransform"
|
||||
},
|
||||
{
|
||||
"Name": "FTimerHandle",
|
||||
"ManagedType": "UnrealSharp.Engine.FTimerHandle"
|
||||
},
|
||||
{
|
||||
"Name": "FInputActionValue",
|
||||
"ManagedType": "UnrealSharp.EnhancedInput.FInputActionValue"
|
||||
},
|
||||
{
|
||||
"Name": "FRandomStream",
|
||||
"ManagedType": "UnrealSharp.CoreUObject.FRandomStream"
|
||||
},
|
||||
{
|
||||
"Name": "FSubsystemCollectionBaseRef",
|
||||
"ManagedType": "UnrealSharp.UnrealSharpCore.FSubsystemCollectionBaseRef"
|
||||
}
|
||||
],
|
||||
"NativelyTranslatableTypes": [
|
||||
{
|
||||
"Name": "FMoverDataCollection",
|
||||
"HasDestructor": false
|
||||
},
|
||||
{
|
||||
"Name": "FPaintContext",
|
||||
"HasDestructor": false
|
||||
},
|
||||
{
|
||||
"Name": "FGeometry",
|
||||
"HasDestructor": false
|
||||
},
|
||||
{
|
||||
"Name": "FGameplayEffectSpec",
|
||||
"HasDestructor": true
|
||||
},
|
||||
{
|
||||
"Name": "FGameplayEffectSpecHandle",
|
||||
"HasDestructor": true
|
||||
},
|
||||
{
|
||||
"Name": "FKeyEvent",
|
||||
"HasDestructor": false
|
||||
},
|
||||
{
|
||||
"Name": "FInputEvent",
|
||||
"HasDestructor": false
|
||||
},
|
||||
{
|
||||
"Name": "FKey",
|
||||
"HasDestructor": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
5
Plugins/UnrealSharp/Config/DefaultUnrealSharp.ini
Normal file
5
Plugins/UnrealSharp/Config/DefaultUnrealSharp.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[CoreRedirects]
|
||||
+ClassRedirects=(OldName="/Script/CSharpForUE.CSClass",NewName="/Script/UnrealSharpCore.CSClass")
|
||||
+StructRedirects=(OldName="/Script/CSharpForUE.CSScriptStruct",NewName="/Script/UnrealSharpCore.CSScriptStruct")
|
||||
+EnumRedirects=(OldName="/Script/CSharpForUE.CSEnum",NewName="/Script/UnrealSharpCore.CSEnum")
|
||||
+ClassRedirects=(OldName="/Script/UnrealSharpCore.CSDeveloperSettings",NewName="/Script/UnrealSharpCore.CSUnrealSharpSettings")
|
||||
18
Plugins/UnrealSharp/Directory.Packages.props
Normal file
18
Plugins/UnrealSharp/Directory.Packages.props
Normal file
@ -0,0 +1,18 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageVersion Include="LanguageExt.Core" Version="4.4.9" />
|
||||
<PackageVersion Include="Mono.Cecil" Version="0.11.6" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.13.9" />
|
||||
<PackageVersion Include="Microsoft.Build" Version="17.13.9" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.13.0" />
|
||||
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageVersion Include="Microsoft.Build.Locator" Version="1.9.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
21
Plugins/UnrealSharp/LICENSE
Normal file
21
Plugins/UnrealSharp/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 UnrealSharp
|
||||
|
||||
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.
|
||||
@ -0,0 +1,47 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef __CORECLR_DELEGATES_H__
|
||||
#define __CORECLR_DELEGATES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define CORECLR_DELEGATE_CALLTYPE __stdcall
|
||||
#ifdef _WCHAR_T_DEFINED
|
||||
typedef wchar_t char_t;
|
||||
#else
|
||||
typedef unsigned short char_t;
|
||||
#endif
|
||||
#else
|
||||
#define CORECLR_DELEGATE_CALLTYPE
|
||||
typedef char char_t;
|
||||
#endif
|
||||
|
||||
#define UNMANAGEDCALLERSONLY_METHOD ((const char_t*)-1)
|
||||
|
||||
// Signature of delegate returned by coreclr_delegate_type::load_assembly_and_get_function_pointer
|
||||
typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_and_get_function_pointer_fn)(
|
||||
const char_t *assembly_path /* Fully qualified path to assembly */,
|
||||
const char_t *type_name /* Assembly qualified type name */,
|
||||
const char_t *method_name /* Public static method name compatible with delegateType */,
|
||||
const char_t *delegate_type_name /* Assembly qualified delegate type name or null
|
||||
or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
|
||||
the UnmanagedCallersOnlyAttribute. */,
|
||||
void *reserved /* Extensibility parameter (currently unused and must be 0) */,
|
||||
/*out*/ void **delegate /* Pointer where to store the function pointer result */);
|
||||
|
||||
// Signature of delegate returned by load_assembly_and_get_function_pointer_fn when delegate_type_name == null (default)
|
||||
typedef int (CORECLR_DELEGATE_CALLTYPE *component_entry_point_fn)(void *arg, int32_t arg_size_in_bytes);
|
||||
|
||||
typedef int (CORECLR_DELEGATE_CALLTYPE *get_function_pointer_fn)(
|
||||
const char_t *type_name /* Assembly qualified type name */,
|
||||
const char_t *method_name /* Public static method name compatible with delegateType */,
|
||||
const char_t *delegate_type_name /* Assembly qualified delegate type name or null,
|
||||
or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
|
||||
the UnmanagedCallersOnlyAttribute. */,
|
||||
void *load_context /* Extensibility parameter (currently unused and must be 0) */,
|
||||
void *reserved /* Extensibility parameter (currently unused and must be 0) */,
|
||||
/*out*/ void **delegate /* Pointer where to store the function pointer result */);
|
||||
|
||||
#endif // __CORECLR_DELEGATES_H__
|
||||
323
Plugins/UnrealSharp/Managed/DotNetRuntime/inc/hostfxr.h
Normal file
323
Plugins/UnrealSharp/Managed/DotNetRuntime/inc/hostfxr.h
Normal file
@ -0,0 +1,323 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef __HOSTFXR_H__
|
||||
#define __HOSTFXR_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define HOSTFXR_CALLTYPE __cdecl
|
||||
#ifdef _WCHAR_T_DEFINED
|
||||
typedef wchar_t char_t;
|
||||
#else
|
||||
typedef unsigned short char_t;
|
||||
#endif
|
||||
#else
|
||||
#define HOSTFXR_CALLTYPE
|
||||
typedef char char_t;
|
||||
#endif
|
||||
|
||||
enum hostfxr_delegate_type
|
||||
{
|
||||
hdt_com_activation,
|
||||
hdt_load_in_memory_assembly,
|
||||
hdt_winrt_activation,
|
||||
hdt_com_register,
|
||||
hdt_com_unregister,
|
||||
hdt_load_assembly_and_get_function_pointer,
|
||||
hdt_get_function_pointer,
|
||||
};
|
||||
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_fn)(const int argc, const char_t **argv);
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_startupinfo_fn)(
|
||||
const int argc,
|
||||
const char_t **argv,
|
||||
const char_t *host_path,
|
||||
const char_t *dotnet_root,
|
||||
const char_t *app_path);
|
||||
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_main_bundle_startupinfo_fn)(
|
||||
const int argc,
|
||||
const char_t** argv,
|
||||
const char_t* host_path,
|
||||
const char_t* dotnet_root,
|
||||
const char_t* app_path,
|
||||
int64_t bundle_header_offset);
|
||||
|
||||
typedef void(HOSTFXR_CALLTYPE *hostfxr_error_writer_fn)(const char_t *message);
|
||||
|
||||
//
|
||||
// Sets a callback which is to be used to write errors to.
|
||||
//
|
||||
// Parameters:
|
||||
// error_writer
|
||||
// A callback function which will be invoked every time an error is to be reported.
|
||||
// Or nullptr to unregister previously registered callback and return to the default behavior.
|
||||
// Return value:
|
||||
// The previously registered callback (which is now unregistered), or nullptr if no previous callback
|
||||
// was registered
|
||||
//
|
||||
// The error writer is registered per-thread, so the registration is thread-local. On each thread
|
||||
// only one callback can be registered. Subsequent registrations overwrite the previous ones.
|
||||
//
|
||||
// By default no callback is registered in which case the errors are written to stderr.
|
||||
//
|
||||
// Each call to the error writer is sort of like writing a single line (the EOL character is omitted).
|
||||
// Multiple calls to the error writer may occure for one failure.
|
||||
//
|
||||
// If the hostfxr invokes functions in hostpolicy as part of its operation, the error writer
|
||||
// will be propagated to hostpolicy for the duration of the call. This means that errors from
|
||||
// both hostfxr and hostpolicy will be reporter through the same error writer.
|
||||
//
|
||||
typedef hostfxr_error_writer_fn(HOSTFXR_CALLTYPE *hostfxr_set_error_writer_fn)(hostfxr_error_writer_fn error_writer);
|
||||
|
||||
typedef void* hostfxr_handle;
|
||||
struct hostfxr_initialize_parameters
|
||||
{
|
||||
size_t size;
|
||||
const char_t *host_path;
|
||||
const char_t *dotnet_root;
|
||||
};
|
||||
|
||||
//
|
||||
// Initializes the hosting components for a dotnet command line running an application
|
||||
//
|
||||
// Parameters:
|
||||
// argc
|
||||
// Number of argv arguments
|
||||
// argv
|
||||
// Command-line arguments for running an application (as if through the dotnet executable).
|
||||
// Only command-line arguments which are accepted by runtime installation are supported, SDK/CLI commands are not supported.
|
||||
// For example 'app.dll app_argument_1 app_argument_2`.
|
||||
// parameters
|
||||
// Optional. Additional parameters for initialization
|
||||
// host_context_handle
|
||||
// On success, this will be populated with an opaque value representing the initialized host context
|
||||
//
|
||||
// Return value:
|
||||
// Success - Hosting components were successfully initialized
|
||||
// HostInvalidState - Hosting components are already initialized
|
||||
//
|
||||
// This function parses the specified command-line arguments to determine the application to run. It will
|
||||
// then find the corresponding .runtimeconfig.json and .deps.json with which to resolve frameworks and
|
||||
// dependencies and prepare everything needed to load the runtime.
|
||||
//
|
||||
// This function only supports arguments for running an application. It does not support SDK commands.
|
||||
//
|
||||
// This function does not load the runtime.
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_dotnet_command_line_fn)(
|
||||
int argc,
|
||||
const char_t **argv,
|
||||
const struct hostfxr_initialize_parameters *parameters,
|
||||
/*out*/ hostfxr_handle *host_context_handle);
|
||||
|
||||
//
|
||||
// Initializes the hosting components using a .runtimeconfig.json file
|
||||
//
|
||||
// Parameters:
|
||||
// runtime_config_path
|
||||
// Path to the .runtimeconfig.json file
|
||||
// parameters
|
||||
// Optional. Additional parameters for initialization
|
||||
// host_context_handle
|
||||
// On success, this will be populated with an opaque value representing the initialized host context
|
||||
//
|
||||
// Return value:
|
||||
// Success - Hosting components were successfully initialized
|
||||
// Success_HostAlreadyInitialized - Config is compatible with already initialized hosting components
|
||||
// Success_DifferentRuntimeProperties - Config has runtime properties that differ from already initialized hosting components
|
||||
// CoreHostIncompatibleConfig - Config is incompatible with already initialized hosting components
|
||||
//
|
||||
// This function will process the .runtimeconfig.json to resolve frameworks and prepare everything needed
|
||||
// to load the runtime. It will only process the .deps.json from frameworks (not any app/component that
|
||||
// may be next to the .runtimeconfig.json).
|
||||
//
|
||||
// This function does not load the runtime.
|
||||
//
|
||||
// If called when the runtime has already been loaded, this function will check if the specified runtime
|
||||
// config is compatible with the existing runtime.
|
||||
//
|
||||
// Both Success_HostAlreadyInitialized and Success_DifferentRuntimeProperties codes are considered successful
|
||||
// initializations. In the case of Success_DifferentRuntimeProperties, it is left to the consumer to verify that
|
||||
// the difference in properties is acceptable.
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_runtime_config_fn)(
|
||||
const char_t *runtime_config_path,
|
||||
const struct hostfxr_initialize_parameters *parameters,
|
||||
/*out*/ hostfxr_handle *host_context_handle);
|
||||
|
||||
//
|
||||
// Gets the runtime property value for an initialized host context
|
||||
//
|
||||
// Parameters:
|
||||
// host_context_handle
|
||||
// Handle to the initialized host context
|
||||
// name
|
||||
// Runtime property name
|
||||
// value
|
||||
// Out parameter. Pointer to a buffer with the property value.
|
||||
//
|
||||
// Return value:
|
||||
// The error code result.
|
||||
//
|
||||
// The buffer pointed to by value is owned by the host context. The lifetime of the buffer is only
|
||||
// guaranteed until any of the below occur:
|
||||
// - a 'run' method is called for the host context
|
||||
// - properties are changed via hostfxr_set_runtime_property_value
|
||||
// - the host context is closed via 'hostfxr_close'
|
||||
//
|
||||
// If host_context_handle is nullptr and an active host context exists, this function will get the
|
||||
// property value for the active host context.
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_property_value_fn)(
|
||||
const hostfxr_handle host_context_handle,
|
||||
const char_t *name,
|
||||
/*out*/ const char_t **value);
|
||||
|
||||
//
|
||||
// Sets the value of a runtime property for an initialized host context
|
||||
//
|
||||
// Parameters:
|
||||
// host_context_handle
|
||||
// Handle to the initialized host context
|
||||
// name
|
||||
// Runtime property name
|
||||
// value
|
||||
// Value to set
|
||||
//
|
||||
// Return value:
|
||||
// The error code result.
|
||||
//
|
||||
// Setting properties is only supported for the first host context, before the runtime has been loaded.
|
||||
//
|
||||
// If the property already exists in the host context, it will be overwritten. If value is nullptr, the
|
||||
// property will be removed.
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_set_runtime_property_value_fn)(
|
||||
const hostfxr_handle host_context_handle,
|
||||
const char_t *name,
|
||||
const char_t *value);
|
||||
|
||||
//
|
||||
// Gets all the runtime properties for an initialized host context
|
||||
//
|
||||
// Parameters:
|
||||
// host_context_handle
|
||||
// Handle to the initialized host context
|
||||
// count
|
||||
// [in] Size of the keys and values buffers
|
||||
// [out] Number of properties returned (size of keys/values buffers used). If the input value is too
|
||||
// small or keys/values is nullptr, this is populated with the number of available properties
|
||||
// keys
|
||||
// Array of pointers to buffers with runtime property keys
|
||||
// values
|
||||
// Array of pointers to buffers with runtime property values
|
||||
//
|
||||
// Return value:
|
||||
// The error code result.
|
||||
//
|
||||
// The buffers pointed to by keys and values are owned by the host context. The lifetime of the buffers is only
|
||||
// guaranteed until any of the below occur:
|
||||
// - a 'run' method is called for the host context
|
||||
// - properties are changed via hostfxr_set_runtime_property_value
|
||||
// - the host context is closed via 'hostfxr_close'
|
||||
//
|
||||
// If host_context_handle is nullptr and an active host context exists, this function will get the
|
||||
// properties for the active host context.
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_properties_fn)(
|
||||
const hostfxr_handle host_context_handle,
|
||||
/*inout*/ size_t * count,
|
||||
/*out*/ const char_t **keys,
|
||||
/*out*/ const char_t **values);
|
||||
|
||||
//
|
||||
// Load CoreCLR and run the application for an initialized host context
|
||||
//
|
||||
// Parameters:
|
||||
// host_context_handle
|
||||
// Handle to the initialized host context
|
||||
//
|
||||
// Return value:
|
||||
// If the app was successfully run, the exit code of the application. Otherwise, the error code result.
|
||||
//
|
||||
// The host_context_handle must have been initialized using hostfxr_initialize_for_dotnet_command_line.
|
||||
//
|
||||
// This function will not return until the managed application exits.
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_run_app_fn)(const hostfxr_handle host_context_handle);
|
||||
|
||||
//
|
||||
// Gets a typed delegate from the currently loaded CoreCLR or from a newly created one.
|
||||
//
|
||||
// Parameters:
|
||||
// host_context_handle
|
||||
// Handle to the initialized host context
|
||||
// type
|
||||
// Type of runtime delegate requested
|
||||
// delegate
|
||||
// An out parameter that will be assigned the delegate.
|
||||
//
|
||||
// Return value:
|
||||
// The error code result.
|
||||
//
|
||||
// If the host_context_handle was initialized using hostfxr_initialize_for_runtime_config,
|
||||
// then all delegate types are supported.
|
||||
// If the host_context_handle was initialized using hostfxr_initialize_for_dotnet_command_line,
|
||||
// then only the following delegate types are currently supported:
|
||||
// hdt_load_assembly_and_get_function_pointer
|
||||
// hdt_get_function_pointer
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_delegate_fn)(
|
||||
const hostfxr_handle host_context_handle,
|
||||
enum hostfxr_delegate_type type,
|
||||
/*out*/ void **delegate);
|
||||
|
||||
//
|
||||
// Closes an initialized host context
|
||||
//
|
||||
// Parameters:
|
||||
// host_context_handle
|
||||
// Handle to the initialized host context
|
||||
//
|
||||
// Return value:
|
||||
// The error code result.
|
||||
//
|
||||
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_close_fn)(const hostfxr_handle host_context_handle);
|
||||
|
||||
struct hostfxr_dotnet_environment_sdk_info
|
||||
{
|
||||
size_t size;
|
||||
const char_t* version;
|
||||
const char_t* path;
|
||||
};
|
||||
|
||||
typedef void(HOSTFXR_CALLTYPE* hostfxr_get_dotnet_environment_info_result_fn)(
|
||||
const struct hostfxr_dotnet_environment_info* info,
|
||||
void* result_context);
|
||||
|
||||
struct hostfxr_dotnet_environment_framework_info
|
||||
{
|
||||
size_t size;
|
||||
const char_t* name;
|
||||
const char_t* version;
|
||||
const char_t* path;
|
||||
};
|
||||
|
||||
struct hostfxr_dotnet_environment_info
|
||||
{
|
||||
size_t size;
|
||||
|
||||
const char_t* hostfxr_version;
|
||||
const char_t* hostfxr_commit_hash;
|
||||
|
||||
size_t sdk_count;
|
||||
const hostfxr_dotnet_environment_sdk_info* sdks;
|
||||
|
||||
size_t framework_count;
|
||||
const hostfxr_dotnet_environment_framework_info* frameworks;
|
||||
};
|
||||
|
||||
#endif //__HOSTFXR_H__
|
||||
99
Plugins/UnrealSharp/Managed/DotNetRuntime/inc/nethost.h
Normal file
99
Plugins/UnrealSharp/Managed/DotNetRuntime/inc/nethost.h
Normal file
@ -0,0 +1,99 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef __NETHOST_H__
|
||||
#define __NETHOST_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef NETHOST_EXPORT
|
||||
#define NETHOST_API __declspec(dllexport)
|
||||
#else
|
||||
// Consuming the nethost as a static library
|
||||
// Shouldn't export attempt to dllimport.
|
||||
#ifdef NETHOST_USE_AS_STATIC
|
||||
#define NETHOST_API
|
||||
#else
|
||||
#define NETHOST_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NETHOST_CALLTYPE __stdcall
|
||||
#ifdef _WCHAR_T_DEFINED
|
||||
typedef wchar_t char_t;
|
||||
#else
|
||||
typedef unsigned short char_t;
|
||||
#endif
|
||||
#else
|
||||
#ifdef NETHOST_EXPORT
|
||||
#define NETHOST_API __attribute__((__visibility__("default")))
|
||||
#else
|
||||
#define NETHOST_API
|
||||
#endif
|
||||
|
||||
#define NETHOST_CALLTYPE
|
||||
typedef char char_t;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Parameters for get_hostfxr_path
|
||||
//
|
||||
// Fields:
|
||||
// size
|
||||
// Size of the struct. This is used for versioning.
|
||||
//
|
||||
// assembly_path
|
||||
// Path to the compenent's assembly.
|
||||
// If specified, hostfxr is located as if the assembly_path is the apphost
|
||||
//
|
||||
// dotnet_root
|
||||
// Path to directory containing the dotnet executable.
|
||||
// If specified, hostfxr is located as if an application is started using
|
||||
// 'dotnet app.dll', which means it will be searched for under the dotnet_root
|
||||
// path and the assembly_path is ignored.
|
||||
//
|
||||
struct get_hostfxr_parameters {
|
||||
size_t size;
|
||||
const char_t *assembly_path;
|
||||
const char_t *dotnet_root;
|
||||
};
|
||||
|
||||
//
|
||||
// Get the path to the hostfxr library
|
||||
//
|
||||
// Parameters:
|
||||
// buffer
|
||||
// Buffer that will be populated with the hostfxr path, including a null terminator.
|
||||
//
|
||||
// buffer_size
|
||||
// [in] Size of buffer in char_t units.
|
||||
// [out] Size of buffer used in char_t units. If the input value is too small
|
||||
// or buffer is nullptr, this is populated with the minimum required size
|
||||
// in char_t units for a buffer to hold the hostfxr path
|
||||
//
|
||||
// get_hostfxr_parameters
|
||||
// Optional. Parameters that modify the behaviour for locating the hostfxr library.
|
||||
// If nullptr, hostfxr is located using the enviroment variable or global registration
|
||||
//
|
||||
// Return value:
|
||||
// 0 on success, otherwise failure
|
||||
// 0x80008098 - buffer is too small (HostApiBufferTooSmall)
|
||||
//
|
||||
// Remarks:
|
||||
// The full search for the hostfxr library is done on every call. To minimize the need
|
||||
// to call this function multiple times, pass a large buffer (e.g. PATH_MAX).
|
||||
//
|
||||
NETHOST_API int NETHOST_CALLTYPE get_hostfxr_path(
|
||||
char_t * buffer,
|
||||
size_t * buffer_size,
|
||||
const struct get_hostfxr_parameters *parameters);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // __NETHOST_H__
|
||||
252
Plugins/UnrealSharp/Managed/Shared/DotNetUtilities.cs
Normal file
252
Plugins/UnrealSharp/Managed/Shared/DotNetUtilities.cs
Normal file
@ -0,0 +1,252 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace UnrealSharp.Shared;
|
||||
|
||||
public static class DotNetUtilities
|
||||
{
|
||||
public const string DOTNET_MAJOR_VERSION = "9.0";
|
||||
public const string DOTNET_MAJOR_VERSION_DISPLAY = "net" + DOTNET_MAJOR_VERSION;
|
||||
|
||||
public static string FindDotNetExecutable()
|
||||
{
|
||||
const string DOTNET_WIN = "dotnet.exe";
|
||||
const string DOTNET_UNIX = "dotnet";
|
||||
|
||||
var dotnetExe = OperatingSystem.IsWindows() ? DOTNET_WIN : DOTNET_UNIX;
|
||||
|
||||
var pathVariable = Environment.GetEnvironmentVariable("PATH");
|
||||
|
||||
if (pathVariable == null)
|
||||
{
|
||||
throw new Exception($"Couldn't find {dotnetExe}!");
|
||||
}
|
||||
|
||||
var paths = pathVariable.Split(Path.PathSeparator);
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
// This is a hack to avoid using the dotnet.exe from the Unreal Engine installation directory.
|
||||
// Can't use the dotnet.exe from the Unreal Engine installation directory because it's .NET 6.0
|
||||
if (!path.Contains(@"\dotnet\"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var dotnetExePath = Path.Combine(path, dotnetExe);
|
||||
|
||||
if (File.Exists(dotnetExePath))
|
||||
{
|
||||
return dotnetExePath;
|
||||
}
|
||||
}
|
||||
|
||||
if ( OperatingSystem.IsMacOS() ) {
|
||||
if ( File.Exists( "/usr/local/share/dotnet/dotnet" ) ) {
|
||||
return "/usr/local/share/dotnet/dotnet";
|
||||
}
|
||||
if ( File.Exists( "/opt/homebrew/bin/dotnet" ) ) {
|
||||
return "/opt/homebrew/bin/dotnet";
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Couldn't find {dotnetExe} in PATH!");
|
||||
}
|
||||
|
||||
public static string GetLatestDotNetSdkPath()
|
||||
{
|
||||
string dotNetExecutable = FindDotNetExecutable();
|
||||
string dotNetExecutableDirectory = Path.GetDirectoryName(dotNetExecutable)!;
|
||||
string dotNetSdkDirectory = Path.Combine(dotNetExecutableDirectory!, "sdk");
|
||||
|
||||
string[] folderPaths = Directory.GetDirectories(dotNetSdkDirectory);
|
||||
|
||||
string highestVersion = "0.0.0";
|
||||
|
||||
foreach (string folderPath in folderPaths)
|
||||
{
|
||||
string folderName = Path.GetFileName(folderPath);
|
||||
|
||||
if (string.IsNullOrEmpty(folderName) || !char.IsDigit(folderName[0]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.Compare(folderName, highestVersion, StringComparison.Ordinal) > 0)
|
||||
{
|
||||
highestVersion = folderName;
|
||||
}
|
||||
}
|
||||
|
||||
if (highestVersion == "0.0.0")
|
||||
{
|
||||
throw new Exception("Failed to find the latest .NET SDK version.");
|
||||
}
|
||||
|
||||
if (!highestVersion.StartsWith(DOTNET_MAJOR_VERSION))
|
||||
{
|
||||
throw new Exception($"Failed to find the latest .NET SDK version. Expected version to start with {DOTNET_MAJOR_VERSION} but found: {highestVersion}");
|
||||
}
|
||||
|
||||
return Path.Combine(dotNetSdkDirectory, highestVersion);
|
||||
}
|
||||
|
||||
public static void BuildSolution(string projectRootDirectory, string managedBinariesPath)
|
||||
{
|
||||
if (!Directory.Exists(projectRootDirectory))
|
||||
{
|
||||
throw new Exception($"Couldn't find project root directory: {projectRootDirectory}");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(managedBinariesPath))
|
||||
{
|
||||
Directory.CreateDirectory(managedBinariesPath);
|
||||
}
|
||||
|
||||
Collection<string> arguments = new Collection<string>
|
||||
{
|
||||
"publish",
|
||||
$"-p:PublishDir=\"{managedBinariesPath}\""
|
||||
};
|
||||
|
||||
InvokeDotNet(arguments, projectRootDirectory);
|
||||
}
|
||||
|
||||
public static bool InvokeDotNet(Collection<string> arguments, string? workingDirectory = null)
|
||||
{
|
||||
string dotnetPath = FindDotNetExecutable();
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = dotnetPath,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
|
||||
foreach (string argument in arguments)
|
||||
{
|
||||
startInfo.ArgumentList.Add(argument);
|
||||
}
|
||||
|
||||
if (workingDirectory != null)
|
||||
{
|
||||
startInfo.WorkingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
// Set the MSBuild environment variables to the latest .NET SDK that U# supports.
|
||||
// Otherwise, we'll use the .NET SDK that comes with the Unreal Engine.
|
||||
{
|
||||
string latestDotNetSdkPath = GetLatestDotNetSdkPath();
|
||||
startInfo.Environment["MSBuildExtensionsPath"] = latestDotNetSdkPath;
|
||||
startInfo.Environment["MSBUILD_EXE_PATH"] = $@"{latestDotNetSdkPath}\MSBuild.dll";
|
||||
startInfo.Environment["MSBuildSDKsPath"] = $@"{latestDotNetSdkPath}\Sdks";
|
||||
}
|
||||
|
||||
using Process process = new Process();
|
||||
process.StartInfo = startInfo;
|
||||
|
||||
try
|
||||
{
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
process.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
outputBuilder.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
|
||||
process.ErrorDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
outputBuilder.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
|
||||
if (!process.Start())
|
||||
{
|
||||
throw new Exception("Failed to start process");
|
||||
}
|
||||
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
process.WaitForExit();
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
string errorMessage = outputBuilder.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(errorMessage))
|
||||
{
|
||||
errorMessage = "Process exited with non-zero exit code but no output was captured.";
|
||||
}
|
||||
|
||||
throw new Exception($"Process failed with exit code {process.ExitCode}: {errorMessage}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool InvokeUSharpBuildTool(string action,
|
||||
string managedBinariesPath,
|
||||
string projectName,
|
||||
string pluginDirectory,
|
||||
string projectDirectory,
|
||||
string engineDirectory,
|
||||
IEnumerable<KeyValuePair<string, string>>? additionalArguments = null)
|
||||
{
|
||||
string dotNetExe = FindDotNetExecutable();
|
||||
string unrealSharpBuildToolPath = Path.Combine(managedBinariesPath, "UnrealSharpBuildTool.dll");
|
||||
|
||||
if (!File.Exists(unrealSharpBuildToolPath))
|
||||
{
|
||||
throw new Exception($"Failed to find UnrealSharpBuildTool.dll at: {unrealSharpBuildToolPath}");
|
||||
}
|
||||
|
||||
Collection<string> arguments = new Collection<string>
|
||||
{
|
||||
unrealSharpBuildToolPath,
|
||||
|
||||
"--Action",
|
||||
action,
|
||||
|
||||
"--EngineDirectory",
|
||||
$"{engineDirectory}",
|
||||
|
||||
"--ProjectDirectory",
|
||||
$"{projectDirectory}",
|
||||
|
||||
"--ProjectName",
|
||||
projectName,
|
||||
|
||||
"--PluginDirectory",
|
||||
$"{pluginDirectory}",
|
||||
|
||||
"--DotNetPath",
|
||||
$"{dotNetExe}"
|
||||
};
|
||||
|
||||
if (additionalArguments != null)
|
||||
{
|
||||
arguments.Add("--AdditionalArgs");
|
||||
|
||||
foreach (KeyValuePair<string, string> argument in additionalArguments)
|
||||
{
|
||||
arguments.Add($"{argument.Key}={argument.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
return InvokeDotNet(arguments);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
namespace UnrealSharp.Binds;
|
||||
|
||||
public static class NativeBinds
|
||||
{
|
||||
private unsafe static delegate* unmanaged[Cdecl]<char*, char*, int, IntPtr> _getBoundFunction = null;
|
||||
|
||||
public unsafe static void InitializeNativeBinds(IntPtr bindsCallbacks)
|
||||
{
|
||||
if (_getBoundFunction != null)
|
||||
{
|
||||
throw new Exception("NativeBinds.InitializeNativeBinds called twice");
|
||||
}
|
||||
|
||||
_getBoundFunction = (delegate* unmanaged[Cdecl]<char*, char*, int, IntPtr>)bindsCallbacks;
|
||||
}
|
||||
|
||||
public unsafe static IntPtr TryGetBoundFunction(string outerName, string functionName, int functionSize)
|
||||
{
|
||||
if (_getBoundFunction == null)
|
||||
{
|
||||
throw new Exception("NativeBinds not initialized");
|
||||
}
|
||||
|
||||
IntPtr functionPtr = IntPtr.Zero;
|
||||
fixed (char* outerNamePtr = outerName)
|
||||
fixed (char* functionNamePtr = functionName)
|
||||
{
|
||||
functionPtr = _getBoundFunction(outerNamePtr, functionNamePtr, functionSize);
|
||||
}
|
||||
|
||||
if (functionPtr == IntPtr.Zero)
|
||||
{
|
||||
throw new Exception($"Failed to find bound function {functionName} in {outerName}");
|
||||
}
|
||||
|
||||
return functionPtr;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
namespace UnrealSharp.Binds;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class NativeCallbacksAttribute : Attribute;
|
||||
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@ -0,0 +1,3 @@
|
||||
namespace UnrealSharp.Core.Attributes;
|
||||
|
||||
public class BindingAttribute : Attribute;
|
||||
@ -0,0 +1,4 @@
|
||||
namespace UnrealSharp.Core.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Struct)]
|
||||
public class BlittableTypeAttribute : Attribute;
|
||||
@ -0,0 +1,17 @@
|
||||
namespace UnrealSharp.Core.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Used to mark a type as generated. Don't use this attribute in your code.
|
||||
/// It's public since glue for user code is generated in the user's project.
|
||||
/// </summary>
|
||||
public class GeneratedTypeAttribute : Attribute
|
||||
{
|
||||
public GeneratedTypeAttribute(string engineName, string fullName = "")
|
||||
{
|
||||
EngineName = engineName;
|
||||
FullName = fullName;
|
||||
}
|
||||
|
||||
public string EngineName;
|
||||
public string FullName;
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace UnrealSharp.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Struct representing a handle to a delegate.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FDelegateHandle : IEquatable<FDelegateHandle>
|
||||
{
|
||||
public ulong ID;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ID = 0;
|
||||
}
|
||||
|
||||
public static bool operator ==(FDelegateHandle a, FDelegateHandle b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(FDelegateHandle a, FDelegateHandle b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is FDelegateHandle handle && Equals(handle);
|
||||
}
|
||||
|
||||
public bool Equals(FDelegateHandle other)
|
||||
{
|
||||
return ID == other.ID;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ID.GetHashCode();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
using UnrealSharp.Binds;
|
||||
|
||||
namespace UnrealSharp.Core;
|
||||
|
||||
[NativeCallbacks]
|
||||
public static unsafe partial class FCSManagerExporter
|
||||
{
|
||||
public static delegate* unmanaged<IntPtr, IntPtr> FindManagedObject;
|
||||
public static delegate* unmanaged<IntPtr, IntPtr, IntPtr> FindOrCreateManagedInterfaceWrapper;
|
||||
public static delegate* unmanaged<IntPtr> GetCurrentWorldContext;
|
||||
public static delegate* unmanaged<IntPtr> GetCurrentWorldPtr;
|
||||
|
||||
public static UnrealSharpObject WorldContextObject
|
||||
{
|
||||
get
|
||||
{
|
||||
IntPtr worldContextObject = CallGetCurrentWorldContext();
|
||||
IntPtr handle = CallFindManagedObject(worldContextObject);
|
||||
return GCHandleUtilities.GetObjectFromHandlePtr<UnrealSharpObject>(handle)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
|
||||
namespace UnrealSharp.Core;
|
||||
|
||||
public static class GCHandleUtilities
|
||||
{
|
||||
private static readonly ConcurrentDictionary<AssemblyLoadContext, ConcurrentDictionary<GCHandle, object>> StrongRefsByAssembly = new();
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static void OnAlcUnloading(AssemblyLoadContext alc)
|
||||
{
|
||||
StrongRefsByAssembly.TryRemove(alc, out _);
|
||||
}
|
||||
|
||||
public static GCHandle AllocateStrongPointer(object value, object allocator)
|
||||
{
|
||||
return AllocateStrongPointer(value, allocator.GetType().Assembly);
|
||||
}
|
||||
|
||||
public static GCHandle AllocateStrongPointer(object value, Assembly alc)
|
||||
{
|
||||
AssemblyLoadContext? assemblyLoadContext = AssemblyLoadContext.GetLoadContext(alc);
|
||||
|
||||
if (assemblyLoadContext == null)
|
||||
{
|
||||
throw new InvalidOperationException("AssemblyLoadContext is null.");
|
||||
}
|
||||
|
||||
return AllocateStrongPointer(value, assemblyLoadContext);
|
||||
}
|
||||
|
||||
public static GCHandle AllocateStrongPointer(object value, AssemblyLoadContext loadContext)
|
||||
{
|
||||
GCHandle weakHandle = GCHandle.Alloc(value, GCHandleType.Weak);
|
||||
ConcurrentDictionary<GCHandle, object> strongReferences = StrongRefsByAssembly.GetOrAdd(loadContext, alcInstance =>
|
||||
{
|
||||
alcInstance.Unloading += OnAlcUnloading;
|
||||
return new ConcurrentDictionary<GCHandle, object>();
|
||||
});
|
||||
|
||||
strongReferences.TryAdd(weakHandle, value);
|
||||
|
||||
return weakHandle;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static GCHandle AllocateWeakPointer(object value) => GCHandle.Alloc(value, GCHandleType.Weak);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static GCHandle AllocatePinnedPointer(object value) => GCHandle.Alloc(value, GCHandleType.Pinned);
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void Free(GCHandle handle, Assembly? assembly)
|
||||
{
|
||||
if (assembly != null)
|
||||
{
|
||||
AssemblyLoadContext? assemblyLoadContext = AssemblyLoadContext.GetLoadContext(assembly);
|
||||
|
||||
if (assemblyLoadContext == null)
|
||||
{
|
||||
throw new InvalidOperationException("AssemblyLoadContext is null.");
|
||||
}
|
||||
|
||||
if (StrongRefsByAssembly.TryGetValue(assemblyLoadContext, out ConcurrentDictionary<GCHandle, object>? strongReferences))
|
||||
{
|
||||
strongReferences.TryRemove(handle, out _);
|
||||
}
|
||||
}
|
||||
|
||||
handle.Free();
|
||||
}
|
||||
|
||||
public static T? GetObjectFromHandlePtr<T>(IntPtr handle)
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
GCHandle subObjectGcHandle = GCHandle.FromIntPtr(handle);
|
||||
if (!subObjectGcHandle.IsAllocated)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
object? subObject = subObjectGcHandle.Target;
|
||||
if (subObject is T typedObject)
|
||||
{
|
||||
return typedObject;
|
||||
}
|
||||
|
||||
return default;
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
using UnrealSharp.Binds;
|
||||
|
||||
namespace UnrealSharp.Core.Interop;
|
||||
|
||||
[NativeCallbacks]
|
||||
public static unsafe partial class FScriptArrayExporter
|
||||
{
|
||||
public static delegate* unmanaged<UnmanagedArray*, IntPtr> GetData;
|
||||
public static delegate* unmanaged<UnmanagedArray*, int, NativeBool> IsValidIndex;
|
||||
public static delegate* unmanaged<UnmanagedArray*, int> Num;
|
||||
public static delegate* unmanaged<UnmanagedArray*, void> Destroy;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using UnrealSharp.Binds;
|
||||
|
||||
namespace UnrealSharp.Interop;
|
||||
|
||||
[NativeCallbacks]
|
||||
public unsafe partial class FStringExporter
|
||||
{
|
||||
public static delegate* unmanaged<IntPtr, char*, void> MarshalToNativeString;
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
using UnrealSharp.Binds;
|
||||
|
||||
namespace UnrealSharp.Core.Interop;
|
||||
|
||||
[NativeCallbacks]
|
||||
public unsafe partial class ManagedHandleExporter
|
||||
{
|
||||
public static delegate* unmanaged<IntPtr, IntPtr, void> StoreManagedHandle;
|
||||
public static delegate* unmanaged<IntPtr, IntPtr> LoadManagedHandle;
|
||||
public static delegate* unmanaged<IntPtr, IntPtr, int, void> StoreUnmanagedMemory;
|
||||
public static delegate* unmanaged<IntPtr, IntPtr, int, void> LoadUnmanagedMemory;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
using UnrealSharp.Log;
|
||||
|
||||
namespace UnrealSharp.Core;
|
||||
|
||||
[CustomLog]
|
||||
public static partial class LogUnrealSharpCore;
|
||||
@ -0,0 +1,31 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace UnrealSharp.Core;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct ManagedCallbacks
|
||||
{
|
||||
public delegate* unmanaged<IntPtr, IntPtr, char**, IntPtr> ScriptManagerBridge_CreateManagedObject;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, IntPtr> ScriptManagerBridge_CreateNewManagedObjectWrapper;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int> ScriptManagerBridge_InvokeManagedMethod;
|
||||
public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_InvokeDelegate;
|
||||
public delegate* unmanaged<IntPtr, char*, IntPtr> ScriptManagerBridge_LookupManagedMethod;
|
||||
public delegate* unmanaged<IntPtr, char*, IntPtr> ScriptManagedBridge_LookupManagedType;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, void> ScriptManagedBridge_Dispose;
|
||||
public delegate* unmanaged<IntPtr, void> ScriptManagedBridge_FreeHandle;
|
||||
|
||||
public static void Initialize(IntPtr outManagedCallbacks)
|
||||
{
|
||||
*(ManagedCallbacks*)outManagedCallbacks = new ManagedCallbacks
|
||||
{
|
||||
ScriptManagerBridge_CreateManagedObject = &UnmanagedCallbacks.CreateNewManagedObject,
|
||||
ScriptManagerBridge_CreateNewManagedObjectWrapper = &UnmanagedCallbacks.CreateNewManagedObjectWrapper,
|
||||
ScriptManagerBridge_InvokeManagedMethod = &UnmanagedCallbacks.InvokeManagedMethod,
|
||||
ScriptManagerBridge_InvokeDelegate = &UnmanagedCallbacks.InvokeDelegate,
|
||||
ScriptManagerBridge_LookupManagedMethod = &UnmanagedCallbacks.LookupManagedMethod,
|
||||
ScriptManagedBridge_LookupManagedType = &UnmanagedCallbacks.LookupManagedType,
|
||||
ScriptManagedBridge_Dispose = &UnmanagedCallbacks.Dispose,
|
||||
ScriptManagedBridge_FreeHandle = &UnmanagedCallbacks.FreeHandle,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
namespace UnrealSharp.Core.Marshallers;
|
||||
|
||||
public static class BitfieldBoolMarshaller
|
||||
{
|
||||
private const int BoolSize = sizeof(NativeBool);
|
||||
|
||||
public static void ToNative(IntPtr valuePtr, byte fieldMask, bool value)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var byteValue = (byte*)valuePtr;
|
||||
var mask = value ? fieldMask : byte.MinValue;
|
||||
*byteValue = (byte)((*byteValue & ~fieldMask) | mask);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool FromNative(IntPtr valuePtr, byte fieldMask)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var byteValue = (byte*)valuePtr;
|
||||
return (*byteValue & fieldMask) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace UnrealSharp.Core.Marshallers;
|
||||
|
||||
public static class BlittableMarshaller<T> where T : unmanaged, allows ref struct
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ToNative(IntPtr nativeBuffer, int arrayIndex, T obj)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
ToNative(nativeBuffer, arrayIndex, obj, sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ToNative(IntPtr nativeBuffer, int arrayIndex, T obj, int size)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
*(T*)(nativeBuffer + arrayIndex * size) = obj;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T FromNative(IntPtr nativeBuffer, int arrayIndex)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
return FromNative(nativeBuffer, arrayIndex, sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T FromNative(IntPtr nativeBuffer, int arrayIndex, int size)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
return *(T*)(nativeBuffer + arrayIndex * size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
namespace UnrealSharp.Core.Marshallers;
|
||||
|
||||
public static class BoolMarshaller
|
||||
{
|
||||
public static void ToNative(IntPtr nativeBuffer, int arrayIndex, bool obj)
|
||||
{
|
||||
BlittableMarshaller<NativeBool>.ToNative(nativeBuffer, arrayIndex, obj.ToNativeBool());
|
||||
}
|
||||
|
||||
public static bool FromNative(IntPtr nativeBuffer, int arrayIndex)
|
||||
{
|
||||
return BlittableMarshaller<NativeBool>.FromNative(nativeBuffer, arrayIndex).ToManagedBool();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user