ET框架---HotFix.LandlordsLoginComponent学习笔记

HotFix.LandlordsLoginComponent学习笔记

请大家关注我的微博:@NormanLin_BadPixel坏像素


通过这个代码,我们终于开始接触具体怎么运用ET框架来运行游戏逻辑了。

我们需要在添加这个组件的时候,在Awake方法里进行初始化,所以我们需要订阅Awake事件,这样当我们在AddComponent的时候,就会调用Awake方法。怎么订阅呢?

[ObjectSystem]//需要有ObjectSystem特性
public class LandlordsLoginComponentAwakeSystem : AwakeSystem<LandlordsLoginComponent>
//继承相对应的抽象类,泛型里传入需要订阅事件的组件
{
    public override void Awake(LandlordsLoginComponent self)
    {
        self.Awake();//调用具体的方法。
    }
}

LandlordsLoginComponent.Awake方法里面很简单,作者注释的很详细了,这里讲一下,在初始话的时候给相应的按钮添加了点击事件,OnLoginOnRegister。这就是我们需要重点看的。

我们之前看了一堆消息调用,消息打包等知识,终于,让我们看到了这一切的起点!如何发起一个连接,我们学的东西终于有用了!

我们先看注册吧。

首先,我们需要跟服务器建立一个链接。

//创建登录服务器连接
IPEndPoint connetRealmEndPoint = NetworkHelper.ToIPEndPoint(GlobalConfigComponent.Instance.GlobalProto.Address);
session = Hotfix.Scene.ModelScene.GetComponent<NetOuterComponent>().Create(connetRealmEndPoint);

经过上面这一步,我们获取到了跟服务器的一个回话信息Session。之后,我们就可以通过这个Session发送信息和接收信息。

这里,我们需要发送一个注册请求并且接收服务器的回复。

//发送注册请求
prompt.text = "正在注册中....";
R2C_Register_Ack r2C_Register_Ack = await session.Call(new C2R_Register_Req() { Account = account.text, Password = password.text }) as R2C_Register_Ack;

需要注意的是,这里的session.Call是一个扩展方法,跟我们之前学的Session里面的Call方法是不同的,原来的Call方法传入的是Model层的IRequest,而在热更层,我们需要扩展一个新的方法,传入HotFix层的IRequest

public static async Task<IResponse> Call(this Session session, IRequest request)
{
    OpcodeTypeComponent opcodeTypeComponent = Hotfix.Scene.GetComponent<OpcodeTypeComponent>();
    byte[] bytes = ProtobufHelper.ToBytes(request);
    ushort opcode = opcodeTypeComponent.GetOpcode(request.GetType());
    PacketInfo packetInfo = await session.Call(opcode, bytes);
    ushort responseOpcode = packetInfo.Opcode;
    Type t = opcodeTypeComponent.GetType(responseOpcode);
    object aa = ProtobufHelper.FromBytes(t, packetInfo.Bytes, packetInfo.Index, packetInfo.Length);
    IResponse response = (IResponse)aa;
    return response;
}

我们来看看跟Model层的有什么区别。

有人会说对象的序列化跟反序列化不一样,其实我们仔细看一下

public Task<IResponse> Call(IRequest request)
...
byte[] bytes = this.Network.MessagePacker.SerializeToByteArray(request);

它是通过指定的打包工具进行序列化,其实demo默认的网络信息打包工具就是Protobuf,这里其实最后会调用的就是

ProtobufHelper.ToBytes(request);

这里可能写成

byte[] bytes = session.Network.MessagePacker.SerializeToByteArray(request);

会保险一点。(纯属个人瞎猜,是否正确?),反序列化也一样。

之后,我们通过获得热更信息的opcodebyte[],通过session.Call(opcode, bytes) 来获取请求的返回信息包。这个方法是通用的。

同样的,我们需要返回的是热更层的IResponse

我们来看看热更层的IRequest都有些什么。我们看到,基本上所有热更层的消息类都存放在HotfixMessage文件里。

通过大量的查阅,我们总结出定义消息的结构。我直接在上面注释了。

//Message特性,并且指定opcode,opcode存放在HotfixOpcode类里面。这样才能会注册入opcodeComponent里面。
[Message(HotfixOpcode.C2R_Register_Req)]
//Protobuf-net的用法,说明这个类可以被Protobuf序列化和反序列化
[ProtoContract]
//partial这个关键字,大家可以自行百度。
//Partial是局部类型的意思。允许我们将一个类、结构或接口分成几个部分,分别实现在几个不同的.cs文件中。C#编译器在编译的时候仍会将各个部分的局部类型合并成一个完整的类
public partial class C2R_Register_Req: IRequest//必须实现IRequest接口,其实就是一个标识
{
    //Protobuf-net的用法,说明这个属性会在对象被序列化和反序列化的时候被识别
    //没有ProtoMember这个特性的属性不会被序列化和反序列化。
    //IsRequired说明这个属性是必须有的,不能为null
    [ProtoMember(1, IsRequired = true)]
    public string Account;

    [ProtoMember(2, IsRequired = true)]
    public string Password;

}

之后我们定义自己的消息类的时候,就可以按照上面的结构来定义。
同样的,IResponse也存放在HotfixMessage文件里,结构跟IRequest差不多,大家自行理解。

当我们接收到服务器返回的结果后,如果注册成功,则进入OnLogin方法,我们来瞅瞅。(失败后的处理就不说了,很简单。)

看过注册,登陆就很简单了。同样的,建立与服务器的连接,发送登陆的请求,接收结果,然后根据返回的结果创建Gate服务器连接,什么是Gate服务器?之后我们讲服务器那边的代码的时候会说,马上就得去讲了。
SessionComponent只是存放了与Gate服务器连接。

后面的作者注释的很详细了,我就不赘述了。

之后会出现许多客户端与服务器进行通话的情况,我们现在只知道客户端是怎么处理消息的,怎么发送消息的,但是并不知道服务器是怎么处理,又是怎么回复的。就像我们的X插入墙上的一个洞,拔出来后我们知道结果是什么,但是我们不知道墙那头到底是什么。(呜~开火车了。)

所以,这里我们就要进入另外一个大世界了,Landlords服务端的学习笔记

2018/4/18补充笔记

我们花了好多好多时间,大致是对服务端有了一定的了解了。也对注册和登陆消息的处理做了详细的跟踪,现在就来补充一下登陆成功后的一些操作。

//保存连接,之后所有请求将通过这个连接发送
SessionComponent sessionComponent = Game.Scene.AddComponent<SessionComponent>();
sessionComponent.Session = gateSession;
Log.Info("登录成功");

//保存本地玩家
User user = Model.ComponentFactory.CreateWithId<User, long>(g2C_LoginGate_Ack.PlayerID, g2C_LoginGate_Ack.UserID);
ClientComponent.Instance.LocalPlayer = user;

//跳转到大厅界面
Hotfix.Scene.GetComponent<UIComponent>().Create(UIType.LandlordsLobby);
Hotfix.Scene.GetComponent<UIComponent>().Remove(UIType.LandlordsLogin);

SessionComponent学习笔记

啊,作者注释的很详细了,根本不需要我讲。

结束语

真是一山更比一山高———————–Norman林

<think>好的,我现在需要解决用户遇到的Isaac Sim中environment.yml文件未找到的错误。用户提到错误是EnvironmentFileNotFound,需要找到丢失的environment.yml文件。首先,我应该回忆一下相关的引用内容。根据引用[1],environment.yml文件通常保存在C:\Users\用户名\AppData\Local\ov\pkg\isaac_sim-版本号路径中。用户可能没有正确安装Isaac Sim,或者安装过程中出现了问题,导致文件未被正确创建。 接下来,我应该考虑可能的解决方法。首先,检查默认路径是否存在该文件。如果不存在,可能需要重新安装Isaac Sim,确保安装过程没有错误。另外,用户可能误删了该文件,或者安装路径被修改过,导致系统找不到文件。此外,用户可能没有正确配置环境变量或路径,导致程序无法定位文件。 另一个可能性是用户手动移动了文件,或者权限问题导致无法访问该路径。需要指导用户检查路径的权限,确保他们有读取权限。如果文件确实丢失,可能需要从备份恢复,或者重新生成该文件。此外,如果用户使用的是旧版本,可能需要升级到最新版本,或者查看官方文档是否有关于environment.yml的生成方法。 还要考虑用户是否在正确的位置寻找该文件。例如,是否路径中的用户名正确,或者版本号是否匹配他们安装的Isaac Sim版本。用户可能输入了错误的路径,或者Isaac Sim的安装位置被更改,需要手动定位文件。 另外,根据引用[2],Isaac Sim可能涉及到仿真环境和Python环境配置。如果environment.yml是用来配置conda环境的,用户可能需要重新创建环境,或者从其他来源获取该文件,比如官方文档或社区支持。可能需要指导用户使用conda命令重新生成环境文件,或者检查是否在项目目录中遗漏了该文件。 最后,如果所有方法都无效,建议用户联系官方支持或查看社区论坛,看看是否有其他用户遇到类似问题,并找到解决方案。需要确保用户按照官方指南操作,避免因步骤错误导致文件丢失。</think>针对Isaac Sim的`environment.yml`文件未找到错误,请按以下步骤排查解决: ### 1. 检查默认安装路径 根据引用[1],文件默认路径为: $$C:\Users\你的用户名\AppData\Local\ov\pkg\isaac_sim-版本号$$ * 验证路径中的`用户名`和`版本号`是否匹配当前系统 * 检查`AppData`文件夹是否已开启隐藏文件夹可见性(Windows系统默认隐藏) ### 2. 重新生成环境文件 若文件被误删,可通过以下方法重建: ```bash # 在Anaconda Prompt中执行 conda env export > environment.yml ``` 注意:需先激活正确的Isaac Sim环境[^1] ### 3. 验证安装完整性 * 通过NVIDIA Omniverse Launcher检查Isaac Sim的安装状态 * 确认安装时勾选了"Environment Configuration"选项 * 尝试通过`ovito`命令验证基础功能: $$ovito --check-environment$$ ### 4. 版本兼容性处理 根据引用[2]的技术栈要求: | 组件 | 要求版本 | |-------|---------| | Python | 3.8 | | PyTorch | 1.10.0 | | CUDA | 11.3 | | Isaac Gym | Preview 4 | 若使用自定义环境,需确保版本匹配。可通过`conda list`命令验证包版本。 ### 5. 高级排查手段 ```python # 路径检测脚本 import os import subprocess def check_isaac_env(): base_path = os.path.expanduser("~/AppData/Local/ov/pkg") env_file = "environment.yml" # 遍历所有安装版本 for dir in os.listdir(base_path): if "isaac_sim" in dir: target_path = os.path.join(base_path, dir, env_file) if os.path.exists(target_path): print(f"Found: {target_path}") return True # 未找到时触发自动修复 subprocess.run(["ovito", "--repair-environment"]) return False ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值