【UE5】UE5与Python Socket通信中文数据接收不全

最近在使用UE的Socket模块与Python服务器进行通信时遇到了一些坑,特此记录一下。

先来复现一下问题,这里只截取关键代码。

UE端:

bool ASoc::SendMsg(const FString& Msg)
{
	TSharedRef<FInternetAddr> TargetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	FString Serialized = Msg;
	bool bSend;
	TCHAR* SeriallizedChar = Serialized.GetCharArray().GetData();
	int32 Size = FCString::Strlen(SeriallizedChar) + 1;
	int32 Sent = 0;
	bSend = SocClient->SendTo((uint8*)TCHAR_TO_UTF8(SeriallizedChar),Size,Sent,*TargetAddr);
	if(bSend)
	{
		UE_LOG(LOGNLPFORUE,Log,TEXT("[To LTP | %d]: %s"),Size,*Msg);
	}
	else
	{
		UE_LOG(LOGNLPFORUE,Log,TEXT("Failed to send Msg to tlp"));
	}
	return bSend;
}

Python端:

def socrecv():
    global data,conn,addr,soc
    while True:
        data = str(conn.recv(recvbuff),'utf-8','ignore')
        print('[recv msg from ue |',sys.getsizeof(data),']: ',repr(data))

def soclisten():
    global soc,bind,conn,addr,recvthread
    soc=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    soc.bind((ip,port))
    soc.listen(5)
    print('server listen...')
    bind = True
    while True:
        conn,addr = soc.accept()
        print(addr,'已接入')
        recvthread = Thread(target=socrecv)
        recvthread.setDaemon(True)
        recvthread.start()   

soclisten()

运行结果:

UE端发送的数据:

LOGNLPFORUE: [To LTP | 45]: {"cmd":"ltp","type":"cws","data":"他叫汤姆去拿外衣"}
LOGNLPFORUE: [To LTP | 102]: {"cmd":"ltp","type":"cws","data":"He told Tom to get the coat, but Tom brought a piece of underwear"}

Python端接收到数据:

[recv msg from ue | 148 ]:  '{"cmd":"ltp","type":"cws","data":"他叫汤'
[recv msg from ue | 151 ]:  '{"cmd":"ltp","type":"cws","data":"He told Tom to get the coat, but Tom brought a piece of underwear"}\x00'

可以看到数据容量并没有超出缓存上限,且Python端接收的数据都有做utf-8的编码转换,但依旧出现了中文数据接收不全,容量更大的英文数据反而没问题。

问题出在了UE端的FSocket::SendTo函数,SendTo函数的定义:

bool FSocket::SendTo(const uint8* Data, int32 Count, int32& BytesSent, const FInternetAddr& Destination)

Data就是我们要发送的字节数据,Count数据的大小,BytesSent记录的是数据的发送进度,Destination是要发送数据的地址。

问题就出在Count的值上,可以看到在上面的代码中我们是直接计算的FString的长度,然后以这个长度作为发送的数据大小,在纯英文的数据中这没有任何问题,但在中文数据中,由于中文编码的特殊性,FString应该有做特殊的编码处理,导致直接计算FString的长度作为发送数据的字节大小其实是小于真实数据大小的,这就导致在UE端发送中文数据时就没有发送完整到数据,所以Python端接收到数据就出现数据不全的问题。

既然知道原因了,接下来就可以解决了。那么我们就需要去找一个计算FString中文数据真实字节数的算法来计算SenTo要发送字节数据大小。

在网上我也没找到相关的算法代码,于是就去请教了一位大佬,大佬给了我一份算法代码:

int32 ASoc::CalcUtf0NumFromString(const FString& Str)
{
	int32 result = 0; 
	for (int i = 0; i < Str.Len(); i++)
	{
		if (Str[i] <= 0x7f)
			result = result + 1;
		else if (Str[i] > 0x7f && Str[i] <= 0x07ff)
			result = result + 2;
		else if (Str[i] > 0x07ff && Str[i] <= 0xffff)
			result = result + 3;
		else
			result = result + 4;
	}
	return result + 1;
}

没有去深究FString的中英文编码,代码我是没看明白的,使用这个算法计算数据的字节大小,就能计算出正确的大小。

然后UE端的代码将int32 Size = FCString::Strlen(SeriallizedChar) + 1;换成int32 Size = CalcUtf0NumFromString(SeriallizedChar);,问题就解决了。

&lt;think&gt;好的,我现在需要帮助用户解决在UE5中如何通过非C++方式为每个动画序列绑定粒子效果的问题。首先,我需要回想一下UE5的相关功能,特别是动画系统和粒子系统的结合使用。用户明确要求使用C++,所以应该集中在蓝图和编辑器内的工具上。 首先,动画序列中绑定粒子效果通常可以通过动画通知(Anim Notify)来实现。我记得UE中有Anim Notify的功能,允许在动画的特定时间点触发事件,比如播放声音或粒子效果。用户可能需要在动画的某一帧触发粒子效果,这时候使用Anim Notify比较合适。 接下来,我应该详细说明步骤。首先,打开动画编辑器,找到需要添加效果的动画序列。然后,在时间轴上添加通知轨道,创建自定义的Anim Notify。这个通知需要关联粒子效果,可能需要在内容浏览器中创建粒子系统,然后在通知中选择该资源。可能需要使用Anim Notify State,因为如果是持续一段时间的粒子效果,比如攻击特效,需要开始和结束时间。 另外,动画蒙太奇(Anim Montage)也可能用得上,用户之前提到过创建蒙太奇动画的步骤,可能需要将粒子效果绑定到蒙太奇中的某个片段。过问题主要针对动画序列,所以重点还是在动画序列本身的通知上。 还要考虑是否需要通过蓝图来触发粒子效果。比如,在角色的蓝图中,当接收到Anim Notify时,执行生成粒子效果的节点。这里可能需要检查是否需要在角色或骨骼网格体组件上添加粒子组件,或者在指定位置生成特效。 另外,粒子系统的位置可能需要绑定到骨骼插槽(Socket),这样特效可以跟随某个骨骼移动。比如,在武器的某个位置添加插槽,然后在Anim Notify中指定生成粒子到该插槽位置。 需要确保步骤清晰,使用C++,只使用编辑器内的操作和蓝图。可能涉及的步骤包括创建粒子系统、设置动画通知、在蓝图中处理通知事件、绑定到骨骼插槽等。同时,要提到如何调试和测试这些效果,确保粒子在正确的时间和位置触发。 最后,用户可能需要了解如何调整粒子效果的参数,比如延迟、持续时间,或者如何在同的动画中复用这些设置。可能还需要提及如何通过复制Anim Notify到其他动画序列,提高效率。 总结一下,步骤应该是:创建粒子系统资源,在动画序列中添加Anim Notify,配置Notify触发粒子,设置粒子生成的位置(如骨骼插槽),通过蓝图处理事件生成特效,测试并调整参数。需要分步骤详细说明,确保用户能够按照指引操作。&lt;/think&gt;在UE5中通过非C++方式为动画序列绑定粒子效果,可以通过动画通知系统结合蓝图可视化编程实现。以下是具体操作步骤: ### 一、基础配置流程 1. **创建粒子系统** - 在内容浏览器右键创建`Niagara系统`或`Cascade粒子系统` - 通过粒子编辑器调整喷射形态、颜色、持续时间等参数[^2] 2. **添加动画通知轨道** - 双击打开动画序列资源 - 在时间轴窗口右键选择`添加通知轨道` - 将播放头定位到需要触发特效的关键帧 3. **绑定粒子通知** - 右键选择`添加通知`&rarr;`新建AnimNotify` - 在细节面板中: ```cpp // 伪代码示例 NotifyName = &quot;SwordTrailEffect&quot; Attach ParticleSystem -&gt; 选择创建好的粒子资源 SocketName = &quot;WeaponTip&quot; // 绑定到骨骼插槽 ``` ### 二、高级配置技巧 1. **骨骼插槽定位** - 在角色骨骼网格体中: - 选择需要挂接特效的骨骼(如武器尖端) - 右键`添加插槽`并命名(建议英文命名) 2. **动态参数控制** ```python # 蓝图逻辑示例 Event AnimNotify_SwordTrailEffect: SpawnEmitterAttached( Template=粒子资源, AttachToComponent=骨骼网格体, SocketName=&quot;WeaponTip&quot;, LocationOffset=(0,0,10), RotationOffset=(90,0,0) ) ``` 可通过`Set Niagara Variable`节点实时调整粒子颜色、速度等参数 3. **特效层级管理** - 在粒子系统细节面板中: - 调整`Translucency Sort Priority`控制渲染层级 - 设置`Collision`参数实现场景交互
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值