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

Unity NTPComponent应用, 实现一个无后端高效获取网络时间的组件

无后端高效获取网络时间的组件

  • 废话不多说,直接上源码
  • m_NowSerivceTime 一个基于你发行游戏地区的时间偏移, 比如北京时区就是 8, 巴西就是-3,美国就是-5
  • using Newtonsoft.Json; 如果这里报错, 就说明项目没有 NewtonsoftJson插件, 没关系,这里你改成Unity内置的就行
  • 总之就一句, 没有必要就直接使用NTPComponent.m_NowUtc, 有时区要求就用 NTPComponent.m_NowSerivceTime, 总之,优势在我!
  • 原理, 这块没必要看,如果有同学有兴趣,可以继续看看

废话不多说,直接上源码

直接新建一个脚本 NTPComponent.cs
将脚本Copy到你的项目,拖入场景节点上
获取UTC时间 NTPComponent.m_NowUtc


using UnityEngine;
using System;
using System.Collections;
using UnityEngine.Networking;
using Newtonsoft.Json;
using System.Globalization;namespace GameContent
{/// <summary>/// 启动游戏后,将所有地址列表遍历/// </summary>[DisallowMultipleComponent]public class NTPComponent : MonoBehaviour{/// <summary>/// 网络时间是否生效中/// </summary>public static bool m_IsValid { get; private set; } = true;/// <summary>/// 当前Utc时间/// </summary>public static DateTime m_NowUtc{get{return m_NowUtcServerDate.AddSeconds( ( int ) ( Time.unscaledTime - m_ServerTimePoint ) );}private set{m_NowUtcServerDate = value;}}/// <summary>/// 当前服务器时间/// </summary>public static DateTime m_NowSerivceTime{get{return m_NowUtc.AddHours( GlobalConfig.TIME_ZONE_OFFSET );}}/// <summary>/// 服务器标记时间对象/// </summary>private static DateTime m_NowUtcServerDate;/// <summary>/// 拉取服务器的标记时间尺/// </summary>private static float m_ServerTimePoint = 0f;/// <summary>/// 是否已经成功拉取到服务器时间/// </summary>private bool m_Inited = false;private void Awake( ){m_NowUtc = DateTime.UtcNow;m_ServerTimePoint = Time.unscaledTime;DontDestroyOnLoad( gameObject );}private void Start( ){
#if !SANDBOX_MODEStartCoroutine( GetNetTimeFromWorldTimeApi() );StartCoroutine( GetNetTimeFromTimeIOApi() );StartCoroutine( GetNetTimeFromGoogleApi() );#elseLog.Green( $"当前是沙盒环境,你可以更改时间 {DateTime.Now}" );
#endif}#region WebApiIEnumerator GetApi( string api, Action<string> callback ){using ( var request = UnityWebRequest.Get( "https://worldtimeapi.org/api/timezone/Etc/UTC" ) ){yield return request.SendWebRequest();try{if ( request.result == UnityWebRequest.Result.Success ){callback( request.downloadHandler.text );}//else//{//    Debug.LogError( $"Failed to fetch server time: {request.error}" );//}}catch ( Exception e ){//不处理}}}struct WorldTimeData{public string datetime;public string timezone;public string utc_offset;}struct TimeIOData{public int year;public int month;public int day;public int hour;public int minute;public int seconds;public string dateTime;public string timeZone;public string dayOfWeek;public bool dstActive;}IEnumerator GetNetTimeFromWorldTimeApi( ){string result = string.Empty;yield return GetApi( "https://worldtimeapi.org/api/timezone/Etc/UTC", _ => result = _ );if ( !string.IsNullOrEmpty( result ) ){var data = JsonConvert.DeserializeObject<WorldTimeData>( result );Debug.Log( $"World Time: {data.datetime}" );if ( TryParseUTCString( data.datetime, out var utcNow ) && utcNow != DateTime.MinValue ){OnPullServerTimeOK( utcNow );}}}IEnumerator GetNetTimeFromTimeIOApi( ){string result = string.Empty;yield return GetApi( "https://timeapi.io/api/Time/current/zone?timeZone=UTC", _ => result = _ );if ( !string.IsNullOrEmpty( result ) ){var data = JsonConvert.DeserializeObject<TimeIOData>( result );Debug.Log( $"Time IO API: {data.dateTime}" );if ( TryParseUTCString( data.dateTime, out var utcNow ) && utcNow != DateTime.MinValue ){OnPullServerTimeOK( utcNow );}}}IEnumerator GetNetTimeFromGoogleApi( ){using ( var request = UnityWebRequest.Get( "https://www.google.com" ) ){yield return request.SendWebRequest();try{if ( request.result == UnityWebRequest.Result.Success ){if ( request.GetResponseHeader( "Date" ) != null ){string serverDate = request.GetResponseHeader( "Date" );Debug.Log( $"Google Server Time: {serverDate}" );var utcDate = ParseServerDateToUTC( serverDate );if ( utcDate != DateTime.MinValue ){OnPullServerTimeOK( utcDate );}}}}catch ( Exception e ){//不处理}}}#endregion#region Common/// <summary>/// Parses a UTC time string into a DateTime object./// </summary>/// <param name="utcString">The UTC time string.</param>/// <returns>A DateTime object in UTC, or DateTime.MinValue if parsing fails.</returns>public static bool TryParseUTCString( string utcString, out DateTime utcNow ){try{// Attempt to parse the string with DateTime.ParseDateTime parsedDate = DateTime.Parse( utcString, null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal );utcNow = parsedDate;return true;}catch ( FormatException ){Debug.Log( "Failed to parse UTC time string." );utcNow = DateTime.MinValue;return false;}}/// <summary>/// Parses a server date string (from HTTP header) into a UTC DateTime object./// </summary>/// <param name="serverDate">The server date string in RFC1123 format.</param>/// <returns>A DateTime object in UTC.</returns>public static DateTime ParseServerDateToUTC( string serverDate ){try{// Use DateTime.ParseExact to parse RFC1123 formatDateTime parsedDate = DateTime.ParseExact(serverDate,"r", // "r" or "R" stands for RFC1123 patternCultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);return parsedDate;}catch ( FormatException ex ){Debug.Log( $"Error parsing server date: {ex.Message}" );return DateTime.MinValue; // Return MinValue to indicate failure}}/// <summary>/// 当服务器拉取到时间后调用, 锁定一次/// </summary>/// <param name="utcTime"></param>private void OnPullServerTimeOK( DateTime utcTime ){if ( m_Inited ) return;m_Inited = true;StopAllCoroutines();m_ServerTimePoint = Time.unscaledTime;m_NowUtc = utcTime;Log.Green( $"获取服务器时间成功: {utcTime}" );}#endregion}
}

m_NowSerivceTime 一个基于你发行游戏地区的时间偏移, 比如北京时区就是 8, 巴西就是-3,美国就是-5

具体根项目运营确认

//这个就是一个全局的定义,自己写一个类或者 写死一个也行
GlobalConfig.TIME_ZONE_OFFSET = 8;

using Newtonsoft.Json; 如果这里报错, 就说明项目没有 NewtonsoftJson插件, 没关系,这里你改成Unity内置的就行

改成 JsonUtility.FromJson( result ); //Unity 内置的Json库
在这里插入图片描述

总之就一句, 没有必要就直接使用NTPComponent.m_NowUtc, 有时区要求就用 NTPComponent.m_NowSerivceTime, 总之,优势在我!

在这里插入图片描述

原理, 这块没必要看,如果有同学有兴趣,可以继续看看

真实时间由两个部分组成, 一个是请求一次得到的 真实云UTC时间, 另外一个是当前游戏的秒数TimePoint
通过 基数 + 秒数偏移。 能在游戏内断网的时候有效获取到真实的云时间
需要注意的是,在游戏启动的时候,你得确保用户是联网的
当然,如果你的游戏是纯单机的,也不会报错,因为在Awake的时候默认用的是本地的TimePoint,如果你用纯单机也就不需要考虑真实的时间, 这里是能保证你的项目能在任何条件下安全的跑起来

在游戏启动的时候获取一个 UTC时间 基数
然后记录当前的游戏运行时间 Time.unscaledTime
获取当前真实的UTC时间时 => UTC时间 基数 + ( 当前游戏运行时间 - 记录时间 ) 秒数偏移

在这里插入图片描述

相关文章:

Unity NTPComponent应用, 实现一个无后端高效获取网络时间的组件

无后端高效获取网络时间的组件 废话不多说&#xff0c;直接上源码m_NowSerivceTime 一个基于你发行游戏地区的时间偏移&#xff0c; 比如北京时区就是 8, 巴西就是-3&#xff0c;美国就是-5using Newtonsoft.Json; 如果这里报错&#xff0c; 就说明项目没有 NewtonsoftJson插件…...

go语言使用zlib压缩[]byte

在Go语言中&#xff0c;可以使用compress/flate和compress/zlib包来实现对[]byte数据的Zlib压缩。下面是一个简单的示例&#xff0c;展示如何使用这些包来压缩一个字节切片&#xff1a; go package main import ( "bytes" "compress/zlib" "fmt"…...

Windows 配置 Tomcat环境

Windows配置Tomcat 1. 介绍 Tomcat是一个开源的、轻量级的Java应用服务器&#xff0c;在Java Web开发领域应用广泛。以下是关于它的详细介绍&#xff1a; 一、基本概念与背景 定义&#xff1a;Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;下…...

【python从入门到精通】-- 第六战:列表和元组

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…...

Python | 数据可视化中常见的4种标注及示例

在Python的数据可视化中&#xff0c;标注&#xff08;Annotation&#xff09;技术是一种非常有用的工具&#xff0c;它可以帮助用户更准确地解释图表中的数据和模式。在本文中&#xff0c;将带您了解使用Python实现数据可视化时应该了解的4种标注。 常见的标注方式 文本标注箭…...

LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器,实例化)

完整代码见&#xff1a;zaizai77/Cherno-OpenGL: OpenGL 小白学习之路 高级GLSL 内建变量 顶点着色器 gl_PointSoze : float 输出变量&#xff0c;用于控制渲染 GL_POINTS 型图元时&#xff0c;点的大小。可用于粒子系统。将其设置为 gl_Position.z 时&#xff0c;可以使点…...

Scala学习记录

dao --------> 数据访问 mode ------> 模型 service ---->业务逻辑 Main -------> UI:用户直接操作&#xff0c;调用Service 改造UI层&#xff1a;...

vue使用pdfh5.js插件,显示pdf文件白屏

pdfh5&#xff0c;展示文件白屏&#xff0c;无报错 实现效果图解决方法(降版本)排查问题过程发现问题查找问题根源1、代码写错了&#xff1f;2、预览文件流的问题&#xff1f;3、pdfh5插件更新了&#xff0c;我的依赖包没更新&#xff1f;4、真相大白 彩蛋 实现效果图 解决方法…...

docker login 出错 Error response from daemon

在自己的Linux服务器尝试登陆docker出错 输入完用户密码之后错误如下&#xff1a; 解决方案 1.打开daemo文件&#xff1a; vim/etc/docker/daemon.json 2.常用的国内Docker 镜像源地址 网易云 Docker 镜像&#xff1a;http://hub-mirror.c.163.com 百度云 Docker 镜像&#x…...

Web 身份认证 --- Session和JWT Token

Web 身份认证 --- Session和JWT Token 方法一: 通过使用Session进行身份认证方法二: 通过JWT token进行身份认证什么是JWTJWT完整流程JWT攻防JWT 如何退出登录JWT的续签 方法一: 通过使用Session进行身份认证 用户第一次请求服务器的时候&#xff0c;服务器根据用户提交的相关信…...

UE5制作倒计时功能

设置画布和文本 文本绑定 格式化时间 转到事件图表&#xff0c;计算时间&#xff0c;时间结束后面的事件可以按自己需求写 进入关卡蓝图&#xff0c;添加倒计时UI...

Linux去除注释和空行

平时查看某些配置文件的时&#xff0c;我们会发现有很多注释&#xff08;如&#xff1a;"#"开头的行&#xff09;&#xff0c;中间还有很多空行&#xff0c;看起来非常费劲&#xff0c;所以在这里总结下如何去除注释和空行的方法。 举例说明 这里选个简单点的文件&a…...

Elasticsearch 7.x入门学习-Spring Data Elasticsearch框架

1 Spring Data框架 Spring Data 是一个用于简化数据库、非关系型数据库、索引库访问&#xff0c;并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷&#xff0c;并支持 map-reduce 框架和云计算数据服务。 Spring Data 可以极大的简化 JPA的写法&#xff0c;…...

网络层IP协议(TCP)

IP协议&#xff1a; 在了解IP协议之前&#xff0c;我们市面上看到的"路由器"其实就是工作在网络层。如下图&#xff1a; 那么网络层中的IP协议究竟是如何发送数据包的呢&#xff1f; IP报头&#xff1a; IP协议的报头是比较复杂的&#xff0c;作为程序猿只需要我们重…...

计算机视觉中的边缘检测算法

摘要&#xff1a; 本文全面深入地探讨了计算机视觉中的边缘检测算法。首先阐述了边缘检测的重要性及其在计算机视觉领域的基础地位&#xff0c;随后详细介绍了经典的边缘检测算法&#xff0c;包括基于梯度的 Sobel 算子算法、Canny 边缘检测算法等&#xff0c;深入剖析了它们的…...

js 常用扩展方法总结+应用

文章目录 js 常用扩展方法总结扩展方法应用选择大型项目 中扩展方法应用选择小型项目中 扩展应用 js 常用扩展方法总结 函数原型&#xff08;prototype&#xff09;扩展方法 介绍&#xff1a;在JavaScript中&#xff0c;通过修改函数的prototype属性可以为该函数创建的所有对象…...

数据结构---图(Graph)

图&#xff08;Graph&#xff09;是一种非常灵活且强大的数据结构&#xff0c;用于表示实体之间的复杂关系。在图结构中&#xff0c;数据由一组节点&#xff08;或称为顶点&#xff09;和连接这些节点的边组成。图可以用于表示社交网络、交通网络、网络路由等场景。 1. 基本概…...

前端解析超图的iserver xml

前端解析超图的iserver xml const res await axios.get(url)const xmlDom new DOMParser().parseFromString(res.data, text/xml);// 获取versionconst version xmlDom.getElementsByTagNameNS(*, ServiceTypeVersion)[0].textContent// 获取layerconst layerDom xmlDom.ge…...

LocalForage 使用指南:统一管理 LocalStorage、WebSQL 和 IndexedDB

前言 在前端开发中&#xff0c;客户端数据存储是一个至关重要的环节。无论是用户偏好设置、缓存内容&#xff0c;还是表单数据&#xff0c;都需要一个高效、可靠的存储方案。浏览器原生提供的 LocalStorage、SessionStorage 和 IndexedDB 等 API 虽然功能强大&#xff0c;但使…...

代码随想录算法训练营第五天-哈希-242.有效的字母异位词

这道题的总体感觉不是很难&#xff0c;但是其完成的思想还是很有趣的利用数据下标来代表字母序列然后遍历两个字符串每个字符&#xff0c;给对应字母下标的数组中一个自增&#xff0c;另一个自减通过查看最后的数组内容是不是0&#xff0c;来判断是不是异位词 #include <io…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...