当前位置: 首页 > news >正文

【Unity网络同步框架 - Nakama研究(二)】

Unity网络同步框架 - Nakama研究(二)

虽说官方文档和网站以及论坛建立的不错,而且还有中文翻译且质量也不错,但是总会遇到一些词不达意,说了但是依旧没懂的部分,甚至问AI也问不出什么东西,所以需要有一些比较明显的博客来记录实战部分

服务端搭建

使用官方推荐的Docker进行安装

  • 在将Docker软件下载到Windows环境后,请确保已安装node-jstypescriptluaGo等环境(后续的对应扩展需要),否则先进行npm相关库的安装,需要翻墙或者镜像库安装。
  • 进入根目录,运行cmd控制台(在文件管理器上方地址栏直接输入cmd),输入docker compose up,即能运行服务器(如需要配置文件见下文)。如果更改模块,需要重新编译运行,请输入docker compose up --build nakama(或者在Docker中停止运行再打开)
  • 如果遇到问题,一般情况是缺少对应的库,或者需要下载的库在墙外,下载超时了,很少会遇到不支持对应的数据库CockroachDB或者PostgreSQL啥的,如果遇到了其他问题,建议上官网或者论坛查查
  • 运行成功后,你应该能在Docker中看到如下:

这代表你的服务端已经正常开启了,接下来我们测试一下对应的一些方法和函数。
我的配置文件docker-compose(官网上也能找到类似的)

version: '3'
services:
  cockroachdb:
    image: cockroachdb/cockroach:latest-v23.1
    command: start-single-node --insecure --store=attrs=ssd,path=/var/lib/cockroach/
    restart: "no"
    volumes:
      - data:/var/lib/cockroach
    expose:
      - "8080"
      - "26257"
    ports:
      - "26257:26257"
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health?ready=1"]
      interval: 3s
      timeout: 3s
      retries: 5

  nakama:
    image: registry.heroiclabs.com/heroiclabs/nakama:3.22.0
    entrypoint:
      - "/bin/sh"
      - "-ecx"
      - >
          /nakama/nakama migrate up --database.address root@cockroachdb:26257 &&
          exec /nakama/nakama --name nakama1 --database.address root@cockroachdb:26257 --logger.level DEBUG --session.token_expiry_sec 7200 --metrics.prometheus_port 9100
    restart: "no"
    links:
      - "cockroachdb:db"
    depends_on:
      - cockroachdb
      - prometheus
    volumes:
      - ./:/nakama/data
    environment:
      - NAKAMA_RUNTIME_PATH=/nakama/data/modules
    expose:
      - "7349"
      - "7350"
      - "7351"
      - "9100"
    ports:
      - "7349:7349"
      - "7350:7350"
      - "7351:7351"
    healthcheck:
      test: ["CMD", "/nakama/nakama", "healthcheck"]
      interval: 10s
      timeout: 5s
      retries: 5

  prometheus:
    image: prom/prometheus
    entrypoint: /bin/sh -c
    command: |
      'sh -s <<EOF
        cat > ./prometheus.yml <<EON
      global:
        scrape_interval:     15s
        evaluation_interval: 15s

      scrape_configs:
        - job_name: prometheus
          static_configs:
          - targets: ['localhost:9090']

        - job_name: nakama
          metrics_path: /
          static_configs:
          - targets: ['nakama:9100']
      EON
      prometheus --config.file=./prometheus.yml
      EOF'
    ports:
      - '9090:9090'

volumes:
  data:

服务器简单测试

布置完了服务器,现在我们应该如何使用以及观察对应的服务器内的数据

  • 为了方便测试,我们在这里先不使用Unity,直接打开一个C#程序,我们只是测试一下而已,按照简单的来。有几个重要的网站需要记一下:
    1. 本地控制台
    2. 接口Api地址(包含clientconsole)
  • 测试代码如下:
using Newtonsoft.Json.Linq;
using System.Text;

class Program
{
	private static readonly string nakamaApiMatchUrl = "http://127.0.0.1:7350/v2/match";
	private static readonly string nakamaApiUrl = "http://127.0.0.1:7350/v2/account/authenticate/device?create=true";
	private static readonly string nakamaApiLogoutUrl = "http://127.0.0.1:7350/v2/session/logout";
	private static readonly string nakamaApiStorageUrl = "http://127.0.0.1:7350/v2/storage";
	private static readonly string nakamaApiKey = "defaultkey";
	private static string nakamaAuthToken = "nakama.autoToken";

	static async Task Main(string[] args)
	{
		await AuthenticateDevice();
		await FetchMatchList();
		await FetchStorageObjectAsync();
		await LogOut();
	}
	
	static async Task AuthenticateDevice()
	{
		try
		{
			var authHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{nakamaApiKey}:"));
	
			var client = new HttpClient();
			client.DefaultRequestHeaders.Add("Authorization", $"Basic {authHeader}");
	
			var postData = new { id = "someuniqueidentifier" };
			var json = Newtonsoft.Json.JsonConvert.SerializeObject(postData);
			var content = new StringContent(json, Encoding.UTF8, "application/json");
	
			var response = await client.PostAsync(nakamaApiUrl, content);
	
			if (response.IsSuccessStatusCode)
			{
				var responseContent = await response.Content.ReadAsStringAsync();
				var responseJson = JObject.Parse(responseContent);
	
				Console.WriteLine("Authentication successful.");
				Console.WriteLine($"Session Token: {responseJson["token"]}");
				if(responseJson.ContainsKey("token"))
					nakamaAuthToken = responseJson["token"].ToString();
			}
			else
			{
				Console.WriteLine($"Error authenticating device: {response.StatusCode}");
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Error occurred: {ex.Message}");
			Console.WriteLine("Please check the URL and network connection. If the issue persists, ensure the URL is correct and the server is running.");
		}
	}
	
	static async Task LogOut()
	{
		try
		{
			var client = new HttpClient();
			client.DefaultRequestHeaders.Add("Authorization", $"Bearer {nakamaAuthToken}");
	
			var response = await client.PostAsync($"{nakamaApiLogoutUrl}", null);
	
			if (response.IsSuccessStatusCode)
			{
				var content = await response.Content.ReadAsStringAsync();
				var _content = JObject.Parse(content);
			}
			else
			{
				Console.WriteLine($"Error : {response.StatusCode}");
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Error occurred: {ex.Message}");
		}
	}
	
	static async Task FetchMatchList()
	{
		try
		{
			var client = new HttpClient();
			client.DefaultRequestHeaders.Add("Authorization", $"Bearer {nakamaAuthToken}");
	
			var response = await client.GetAsync($"{nakamaApiMatchUrl}?limit=10&min_size=1&max_size=10");
	
			if (response.IsSuccessStatusCode)
			{
				var content = await response.Content.ReadAsStringAsync();
				var matches = JObject.Parse(content);
	
				if(matches.ContainsKey("matches"))
				{
					foreach (var match in matches["matches"])
					{
						Console.WriteLine($"Match ID: {match["match_id"]}, Size: {match["size"]}");
					}
				}
				else
				{
					Console.WriteLine($"Match list is empty");
				}
			}
			else
			{
				Console.WriteLine($"Error fetching match list: {response.StatusCode}");
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Error occurred: {ex.Message}");
		}
	}
	
	static async Task FetchStorageObjectAsync()
	{
		try
		{
			var client = new HttpClient();
			client.DefaultRequestHeaders.Add("Authorization", $"Bearer {nakamaAuthToken}");
	
			var response = await client.GetAsync($"{nakamaApiStorageUrl}/test/0ba39c8d-5b3d-429d-a570-85af6df61b49");
	
			if (response.IsSuccessStatusCode)
			{
				var content = await response.Content.ReadAsStringAsync();
				var storageContent = JObject.Parse(content);
			}
			else
			{
				Console.WriteLine($"Error fetching match list: {response.StatusCode}");
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Error occurred: {ex.Message}");
		}
	}

}
  • 上面的代码中简单测试了几个功能部分:登录,获取比赛(房间)列表,存储数据,登出。
  • 其中有一些坑需要注意一下:
    • 上面的配置中,不同的服务有不同的端口,其中7350是http请求的端口,也能自行指定
    • Nakama中的比赛(房间)分为权威(服务器创建)和非权威(玩家自创建),要注意区分(查询时会返回不同)
    • 存储分为服务器内存的存储和数据库本地的持久存储,上面的测试是一个临时行的测试,请求的全文是/v2/storage/{collection}/{userId},如果需要严格测试的话,该测试需要后期进行才能跑通
  • 运行
    如果成功的话,运行的结果应该是上面类似(有部分数据没有打印出来,偷懒直接断点看了)

相关文章:

  • 基于NXP+FPGA永磁同步电机牵引控制单元(单板结构/机箱结构)
  • Simulink指导手册笔记②--快捷键及基本操作
  • C51 Proteus仿真实验17:数码管显示4×4键盘矩阵按键
  • CesiumforUE中Cesium3DTileset中高频使用的组件概述
  • 【最新】 ubuntu24安装 1panel 保姆级教程
  • Flutter PopScope对于iOS设置canPop为false无效问题
  • 网络安全信息收集[web子目录]:dirsearch子目录爆破全攻略以及爆破字典结合
  • 用python代码将excel中的数据批量写入Json中的某个字段,生成新的Json文件
  • 如何判断一个项目用的是哪个管理器
  • PhotoMill X for Mac v2.8.1 图片批量编辑工具 支持M、Intel芯片
  • TypeScript 高级类型 vs JavaScript:用“杂交水稻”理解类型编程
  • AWK 入门教程:强大的文本处理工具
  • 区块链知识点2
  • Blender学习方法与技巧
  • React19源码系列之FiberRoot节点和Fiber节点
  • Linux网络编程——UDP网络通信的简单实现
  • Android UI 组件系列(二):Button 进阶用法
  • 第五天 Labview数据记录(5.4 EXCEL文件读写)
  • 安装 oepn-webui报错 Cannot connect to host api.openai.com:443 ssl
  • 网络空间安全(31)安全巡检
  • 受美关税影响,本田预计新财年净利下降七成,并推迟加拿大建厂计划
  • 香港暂停进口美国北达科他州一地区禽肉及禽类产品
  • 全国重点网络媒体和网络达人走进沧州,探寻“文武双全”的多重魅力
  • 航行警告:渤海海峡黄海北部执行军事任务,禁止驶入
  • 印度外交秘书:印巴军方将于12日再次对话
  • 马上评丨全民定制公交,打开城市出行想象空间