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

【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},如果需要严格测试的话,该测试需要后期进行才能跑通
  • 运行
    如果成功的话,运行的结果应该是上面类似(有部分数据没有打印出来,偷懒直接断点看了)

http://www.kler.cn/a/586712.html

相关文章:

  • Spark 中创建 DataFrame 的2种方式对比
  • 【最后203篇系列】015 几种消息队列的思考
  • docker后台运行,便于后期用命令行进入它的终端
  • 【vscode-03】AUTOSAR CP 插件配置
  • DataWhale 速通AI编程开发:(进阶篇)第3章 提示词(Prompts)配置项
  • AI与人的智能,改变一生的思维模型【7】易得性偏差
  • 空调acwing二进制差分
  • C++移动语义与右值引用:从理论到实践的深度解析引言
  • python:数据类构建器
  • 《DeepSeek深度使用教程:开启智能交互新体验》Deepseek深度使用教程
  • 【大模型基础_毛玉仁】2.4 基于 Encoder-Decoder 架构的大语言模型
  • AtCoder Beginner Contest 003(A - 社の給料、B -トランプ、C -プログラミング講座、D - 社の冬 )题目讲解
  • 【PHP】新版本特性记录(持续更新)
  • java 的标记接口RandomAccess使用方法
  • vulnhub靶场之stapler靶机
  • MIDI,AI 3D场景生成技术
  • Audacity 技术浅析(一)
  • [CISSP] [3] 人员安全与社会工程
  • 原生微信小程序实现导航漫游(Tour)
  • 农作物病害数据集