Skip to content

Commit

Permalink
pushmodel
Browse files Browse the repository at this point in the history
  • Loading branch information
RenderTool committed Nov 26, 2024
1 parent 9b6763e commit 0b60bf7
Show file tree
Hide file tree
Showing 20 changed files with 302 additions and 5 deletions.
Binary file added src/.vuepress/public/assets/unrealgif/hpup43.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/.vuepress/public/assets/unrealgif/hpup44.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_002.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_003.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_006.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_007.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_008.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_009.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_011.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_012.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_013.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_014.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_015.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/unreal/assets/aheroselect_016.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
270 changes: 270 additions & 0 deletions src/unreal/master[入魔]/2-MultiWorld.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
---
title: M.MultiWorld|游戏中打开仓库
order : 200
category:
- u++
---

## 导言

>当你试图在游戏中切换英雄或打开背包时,你面临的第一个问题就是怎么打开这些带有独立光照、背景的场景,并且不影响原本的世界。
<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
BABA!我心血来潮想做个类似黑猴的个人仓库
</chatmessage>

![](..%2Fassets%2Faheroselect_002.jpg)

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
费了一番功夫实现后才意识到我的个人仓库界面是带有独立灯光、背景的场景(Level),问题来了!怎么在游戏中打开使用?
</chatmessage>

![](..%2Fassets%2Faheroselect_001.png)


## 问题

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
这个问题的难点可以拆分总结成以下几点:
</chatmessage>

1. 场景切换问题。
2. UI切换问题。
3. 控制器切换问题


<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
让我们看看一些优秀的游戏设计思路吧
</chatmessage>

1. 守望先锋

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
细心的你应该发现当你试图在守望中切换英雄时,他会将角色居中并将镜头固定到场景的某处。甚至某些地图的进攻方可以看到防守方的赛前占位,
</chatmessage>

![](..%2Fassets%2Faheroselect_003.jpg)

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
我想起来了,之前监测站用猩猩站在角落会挡住选择的英雄。
</chatmessage>


<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
要自己注意原始Pawn的生命周期,比如死亡重生时重新赋值等,可惜光照、背景切换颇费功夫。
比如需要将当前场景所有物体隐藏
</chatmessage>

:::note
这里只是简单的演示,远没有我们想要的效果。
:::

<gifwithbutton src="../../assets/unrealgif/hpup43.gif"/>

![](..%2Fassets%2Faheroselect_004.png)


2. 永劫无间

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
永劫的角色界面则是独立的背景、光照的场景。
</chatmessage>

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
如果要改变光照、背景我能想到的方案是用关卡实例来实现。
</chatmessage>

<gifwithbutton src="../../assets/unrealgif/hpup44.gif"/>

1. 主关卡不再存东西,而是动态子关卡代替
2. 子关卡则包括角色选择关卡、游戏地图关卡、背包关卡等

![](..%2Fassets%2Faheroselect_005.png)

## 重识UWorld

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
这里特别强调一下UE中非常反直觉的设定,Level不代表World,Level只是World中维护的一个指针,Level中则维护一堆Actor.
这也是我们经常看到OpenLevel而不是OpenWorld的原因。
</chatmessage>

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
这就涉及到我的盲区了!
</chatmessage>

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
很简单,打开官方文档即源码,翻译一下注释就知道了。
</chatmessage>

![](..%2Fassets%2Faheroselect_009.png)

>官方定义
![](..%2Fassets%2Faheroselect_010.png)

>编辑器之所以可以切换显示图层,也是因为代码中Layers部分是只编译在编辑器中的`WITH_EDITORONLY_DATA`
![](..%2Fassets%2Faheroselect_007.png)

>当然官方也用了专门的子系统维护关卡的图层。
![](..%2Fassets%2Faheroselect_008.png)

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
UE官方特有的废弃特色,一言不合就废弃,从不考虑用户感受,就和增强输入系统一样,config说废就废,也不给一点迁移建议。
</chatmessage>

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
等会,你前面说World维护Level,Level中只有Actor?
</chatmessage>

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
遇事不决,源码走起。
</chatmessage>

![](..%2Fassets%2Faheroselect_011.png)

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
可是这些子关卡并不是Actor啊
</chatmessage>

![](..%2Fassets%2Faheroselect_006.png)

## ULevel & ULevelStreamingDynamic && ULevelStream

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
这就要看看他是如何处理加载这些关卡实例了。
</chatmessage>

![](..%2Fassets%2Faheroselect_012.png)

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
一但我们调用LoadLevelInstanceBySoftObjectPtr,最终走向是在UWrold中调用AddStreamingLevel,下面是一个简单的流程。
</chatmessage>

1. LoadLevelInstanceBySoftObjectPtr,通过世界上下文,拿到具体的世界。早在GamePlay开篇我们就对WorldContextObject
做了简单的介绍,它是由Engine维护的一个方法,用于获取世界指针,再深入就有点不礼貌了。

2. LoadLevelInstance_Internal ,则是LoadLevelInstanceBySoftObjectPtr中调用的私有工具函数,主要是用于包体PackagePath检查、实例化ULevelStreamingDynamic

3. 最终通过World->AddStreamingLevel(StreamingLevel);


>下面是老生常谈的通过上下文拿到UWorld的方法
```cpp
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);

UWorld* UEngine::GetWorldFromContextObject(const UObject* Object, EGetWorldErrorMode ErrorMode) const
{
if (Object == nullptr)
{
switch (ErrorMode)
{
case EGetWorldErrorMode::Assert:
check(Object);
break;
case EGetWorldErrorMode::LogAndReturnNull:
FFrame::KismetExecutionMessage(TEXT("A null object was passed as a world context object to UEngine::GetWorldFromContextObject()."), ELogVerbosity::Warning);
//UE_LOG(LogEngine, Warning, TEXT("UEngine::GetWorldFromContextObject() passed a nullptr"));
break;
case EGetWorldErrorMode::ReturnNull:
break;
}
return nullptr;
}

bool bSupported = true;
UWorld* World = (ErrorMode == EGetWorldErrorMode::Assert) ? Object->GetWorldChecked(/*out*/ bSupported) : Object->GetWorld();
if (bSupported && (World == nullptr) && (ErrorMode == EGetWorldErrorMode::LogAndReturnNull))
{
FFrame::KismetExecutionMessage(*FString::Printf(TEXT("No world was found for object (%s) passed in to UEngine::GetWorldFromContextObject()."), *GetPathNameSafe(Object)), ELogVerbosity::Warning);
}
return (bSupported ? World : GWorld);
}
```
<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
所以讲了这么多ULevel和ULevelStreamingDynamic又是什么关系呢?你不是所有Actor都放在ULevel里吗?
</chatmessage>
<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
ULevelStreamingDynamic既然是从pakage里实例出来的,当然已经包括了ULevel指针
</chatmessage>
![](..%2Fassets%2Faheroselect_013.png)
<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
搜得寺内!我说咱们没法从LevelStreamingDynamic里拿到所有Actor,原来还有这么一层关系啊。
</chatmessage>
```cpp
void UExorcistFunctionLibrary::SetHiddenFromStreamLevel(bool bHidden, ULevelStreaming* LevelStreaming)
{
if (!LevelStreaming) return;
//从LevelStreaming中拿到ULevel
ULevel* LoadedLevel = LevelStreaming->GetLoadedLevel();
if (!LoadedLevel) return;
// ULevel拿到所有的Actor
for(auto Actor : LoadedLevel->Actors)
{
Actor->SetActorHiddenInGame(bHidden);
}
}
```

>所以要从世界拿到所有的Actor的流程是UWorld->ULevelStream->ULevel->Actor,而ULevelStreamingDynamic : public ULevelStreaming,本质还是ULevelStreaming

## UI|Viewport

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
?非常奇怪的问题,为什么没有UI?
</chatmessage>

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
UI并不是UWorld维护的,而是UGameViewportClient维护的SOverlay
</chatmessage>

<chatmessage avatar="../../assets/emoji/hh.png" :avatarWidth="40">
坏了!涉及到更大的盲区了!
</chatmessage>

![](..%2Fassets%2Faheroselect_014.png)

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
硬啃当然不知所以然,我们可以从UI的创建流程反推一下。
</chatmessage>

![](..%2Fassets%2Faheroselect_015.png)

```cpp
void UUserWidget::AddToViewport(int32 ZOrder)
{
if (UGameViewportSubsystem* Subsystem = UGameViewportSubsystem::Get(GetWorld()))
{
FGameViewportWidgetSlot ViewportSlot;
if (bIsManagedByGameViewportSubsystem)
{
ViewportSlot = Subsystem->GetWidgetSlot(this);
}
ViewportSlot.ZOrder = ZOrder;
Subsystem->AddWidget(this, ViewportSlot);
}
}
```
>日常子系统维护,UGameViewportSubsystem : public UEngineSubsystem
![aheroselect_016.png](..%2Fassets%2Faheroselect_016.png)
### TakeWidget
<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>
这里比较关键的就是UWidget 和 SWidget互转函数了,这也是我们以后将UWidget 转成 SWidget一些参考。
</chatmessage>
37 changes: 32 additions & 5 deletions src/unreal/network[网络]/2.3.2-GamePlayNetWork.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,50 @@ ReplicatedUsing定义

![](..%2Fassets%2Fserverrpc012.png)

### 4.C++ PushModel
### 4. C++ PushModel

<chatmessage avatar="../../assets/emoji/bqb (2).png" :avatarWidth="40" alignLeft>

`PushModel` 机制时,复制系统依赖于开发者明确标记属性为脏来触发网络复制。这意味着即使属性发生了变化,如果没有手动标记,系统不会将其复制到客户端。

</chatmessage>

1. **配置项目Config-**DefaultEngine.ini** **

1. **引入必要的头文件**
```cpp
[SystemSettings]
net.IsPushModelEnabled=1
net.PushModelSkipUndirtiedReplication=1
```

2. **Server.Target.cs中,bWithPushModel 也必须设置为 true。**

```cpp
public PushModelNetworkingServerTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Server;

bWithPushModel = true;

//...
}
```
3. **引入必要的头文件和模块引用**
```cpp
#include "Net/UnrealNetwork.h"
#include "Net/Core/PushModel/PushModel.h"
```

2. **定义类和属性**
>NetCore 模块引用添加到我们的 build.cs
```cpp
PrivateDependencyModuleNames.AddRange(new string[] { "NetCore" });
```
4. **定义类和属性**
定义属性,确保被标记为可复制,并使用 `ReplicatedUsing` 指定相应的通知函数。
Expand Down Expand Up @@ -138,7 +165,7 @@ protected:
};
```

3. **实现复制通知函数**
5. **实现复制通知函数**

实现 `OnRep_Array``OnRep_ArrayTrigger` 函数。

Expand All @@ -158,7 +185,7 @@ void AYourClass::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifeti
}
```
4. **手动标记属性为脏**
6. **手动标记属性为脏**
在修改数组内容时,使用 `PushModel` 手动标记属性为脏。
Expand Down

0 comments on commit 0b60bf7

Please sign in to comment.