ET介绍——强大的MongoBson库

强大的MongoBson库

后端开发,统计了一下大概有这些场景需要用到序列化:

  1. 对象通过序列化反序列化clone
  2. 服务端数据库存储数据,二进制
  3. 分布式服务端,多进程间的消息,二进制
  4. 后端日志,文本格式
  5. 服务端的各种配置文件,文本格式

C#序列化库有非常非常多了,protobuf,json等等。但是这些序列化库都无法应当所有场景,既要可读又要小。protobuf不支持复杂的对象结构(无法使用继承),做消息合适,做数据库存储和日志格式并不好用。json做日志格式合适,但是做网络消息和数据存储就太大。我们当然希望一个库能满足上面所有场景,理由如下:

  1. 你想想某天你的配置文件需要放到数据库中保存,你不需要进行格式转换,后端直接把前端发过来的配置消息保存到数据库中,这是不是能减少非常多错误呢?
  2. 某天有些服务端的配置文件不用文件格式了,需要放在数据库中,同样,只需要几行代码就可以完成迁移。
  3. 某天后端服务器crash,你需要扫描日志进行数据恢复,把日志进行反序列化成C#对象,一条条进行处理,再转成对象保存到数据库就完成了。
  4. 对象保存在数据库,直接就可以看到文本内容,可以做各种类sql的操作
  5. 想像一个场景,一个配置文本对象,反序列化到内存,通过网络消息发送,存储到数据库中。整个过程一气呵成。

简单来说就是减少各种数据转换,减少代码,提高开发效率,提高可维护性。当然,Mongo Bson就能够满足。MongoDB库既可以序列化成文本也可以序列化成BSON的二进制格式,并且MongoDB本身就是一个游戏中使用非常多的数据库。Mongo Bson非常完善,是我见过功能最全使用最强大的序列化库,有些功能十分贴心。其支持功能如下:

  1. 支持复杂的继承结构
  2. 支持忽略某些字段序列化
  3. 支持字段默认值
  4. 结构多出多余的字段照样可以反序列化,这对多版本协议非常有用
  5. 支持ISupportInitialize接口使用,这个在反序列化的时候简直就是神器
  6. 支持文本json和二进制bson序列化
  7. MongoDB数据库支持

简单的介绍下mongo bson库

1.支持序列化反序列化成json或者bson

public sealed class Player
    {
        public long Id;

        public string Account { get; private set; }

        public long UnitId { get; set; }
    }

    Player player1 = new Player() { Id = 1 };
    string json = player1.ToJson();
    Console.WriteLine($"player1 to json: {json}");
    Console.WriteLine($"player to bson: {player.ToBson().ToHex()}");
    // output:
    // player to json: { "_id" : NumberLong(1), "C" : [], "Account" : null, "UnitId" : NumberLong(0) }
    // player to bson: B000000125F69640001000000000000000A4163636F756E740012556E6974496400000000000000000000

 

注意mongo的json跟标准的json有点区别,如果想用标准的json,可以传入一个JsonWriterSettings对象,限制使用JsonOutputMode.Strict模式

// 使用标准json
    Player player2 = new Player() { Id = 1 };
    Console.WriteLine($"player to json: {player2.ToJson(new JsonWriterSettings() {OutputMode = JsonOutputMode.Strict})}");
    // player to json: { "_id" : 1, "C" : [], "Account" : null, "UnitId" : 0 }

 

反序列化json:

            // 反序列化json
        Player player11 = BsonSerializer.Deserialize<Player>(json);
        Console.WriteLine($"player11 to json: {player11.ToJson()}");

 

反序列化bson:

    // 反序列化bson
    using (MemoryStream memoryStream = new MemoryStream(bson))
    {
        Player player12 = (Player) BsonSerializer.Deserialize(memoryStream, typeof (Player));
        Console.WriteLine($"player12 to json: {player12.ToJson()}");
    }

 

2.可以忽略某些字段

[BsonIgnore]该标签用来禁止字段序列化。

    public sealed class Player
    {
        public long Id;

        [BsonIgnore]
        public string Account { get; private set; }
        
        public long UnitId { get; set; }
    }

    Player player = new Player() { Id = 2, UnitId = 3, Account = "panda"};
    Console.WriteLine($"player to json: {player.ToJson()}");
    // player to json: { "_id" : 2, "UnitId" : 3 }

 

3.支持默认值以及取别名

[BsonElement] 字段加上该标签,即使是private字段也会序列化(默认只序列化public字段),该标签还可以带一个string参数,给字段序列化指定别名。

    public sealed class Player
    {
        public long Id;

        public string Account { get; private set; }

        [BsonElement("UId")]
        public long UnitId { get; set; }
    }
    Player player = new Player() { Id = 2, UnitId = 3, Account = "panda"};
    Console.WriteLine($"player to json: {player.ToJson()}");
    // player to json: { "_id" : 2, "Account" : "panda", "UId" : 3 }

 

4.升级版本支持

[BsonIgnoreExtraElements] 该标签用在class上面,反序列化时用来忽略多余的字段,一般版本兼容需要考虑,低版本的协议需要能够反 序列化高版本的内容,否则新版本加了字段,旧版本结构反序列化会出错

    [BsonIgnoreExtraElements]
    public sealed class Player
    {
        public long Id;

        public string Account { get; private set; }

        [BsonElement("UId")]
        public long UnitId { get; set; }
    }

 

5.支持复杂的继承结构

mongo bson库强大的地方在于完全支持序列化反序列化继承结构。需要注意的是,继承反序列化需要注册所有的父类,有两种方法: a. 你可以在父类上面使用[BsonKnownTypes]标签声明继承的子类,这样mongo会自动注册,例如:

    [BsonKnownTypes(typeof(Entity))]
    public class Component
    {
    }
    [BsonKnownTypes(typeof(Player))]
    public class Entity: Component
    {
    }
    public sealed class Player: Entity
    {
        public long Id;
        
        public string Account { get; set; }
        
        public long UnitId { get; set; }
    }

 

这样有缺陷,因为框架并不知道一个类会有哪些子类,这样做对框架代码有侵入性,我们希望能解除这个耦合 。可以扫描程序集中所有子类父类的类型,将他们注册到mongo驱动中

            Type[] types = typeof(Game).Assembly.GetTypes();
            foreach (Type type in types)
            {
                if (!type.IsSubclassOf(typeof(Component)))
                {
                    continue;
                }

                BsonClassMap.LookupClassMap(type);
            }

            BsonSerializer.RegisterSerializer(new EnumSerializer<NumericType>(BsonType.String));

 

这样完全的自动化注册,使用者也不需要关心类是否注册。

6.ISupportInitialize接口

mongo bson反序列化时支持一个ISupportInitialize接口,ISupportInitialize有两个方法

    public interface ISupportInitialize
    {
        void BeginInit();
        void EndInit();
    }

 

BeginInit在反序列化前调用,EndInit在反序列化后调用。这个接口非常有用了,可以在反序列化后执行一些操作。例如

    [BsonIgnoreExtraElements]
    public class InnerConfig: AConfigComponent
    {
        [BsonIgnore]
        public IPEndPoint IPEndPoint { get; private set; }
        
        public string Address { get; set; }

        public override void EndInit()
        {
            this.IPEndPoint = NetworkHelper.ToIPEndPoint(this.Address);
        }
    }

 

InnerConfig是ET中进程内网地址的配置,由于IPEndPoint不太好配置,我们可以配置成string形式,然后反序列化的时候在EndInit中把string转换成IPEndPoint。 同样我给protobuf反序列化方法也加上了这个调用,参考ProtobufHelper.cs,ET的protobuf因为要支持ilruntime,所以去掉了map的支持,假如我们想要一个map怎么办呢?这里我给生成的代码都做了手脚,把proto消息都改成了partial class,这样我们可以自己扩展这个class,比如:

message UnitInfo
{
    int64 UnitId  = 1;

    float X = 2;
    float Y = 3;
    float Z = 4;
}

// protobuf
message G2C_EnterMap // IResponse
{
    int32 RpcId = 90;
    int32 Error = 91;
    string Message = 92;
    // 自己的unit id
    int64 UnitId = 1;
    // 所有的unit
    repeated UnitInfo Units = 2;
}

 

这个网络消息有个repeated UnitInfo字段,在protobuf中其实是个数组,使用起来不是很方便,我希望转成一个Dictionary<Int64, UnitInfo>的字段,我们可以做这样的操作:

    public partial class G2C_EnterMap: ISupportInitialize
    {
        public Dictionary<Int64, UnitInfo> unitsDict = new Dictionary<long, UnitInfo>();
        
        public void BeginInit()
        {
        }

        public void EndInit()
        {
            foreach (var unit in this.Units)
            {
                this.unitsDict.Add(unit.UnitId, unit);
            }
        }
    }

 

通过这样一段代码把消息进行扩展一下,反序列化出来之后,自动转成了一个Dictionary。

ET开源地址地址:egametang/ET: Unity3D Client And C# Server Framework (github.com)   qq群:474643097

本文转载于网络 如有侵权请联系删除

相关文章

  • 深度知识的6个维度:如何让人工智能真正理解世界?

    智能的真正标志不是知识,而是想象力。作者|GadiSinger编译|王玥编辑|陈彩娴什么知识让我们变得聪明?我们用来理解世界、解释新体验和做出深思熟虑的选择的认知结构是什么?定义一个阐明给人类或人工智能更深入理解和更高认知的知识的框架,将有助于我们对此话题进行结构化的讨论。近日,英特尔实验室副总裁兼紧急人工智能研究主任GadiSinger介绍了这种赋予人工智能更高认知的知识构建(knowledgeconstructs)的数个维度,并指出一条通往更高智能机器的道路。图为英特尔实验室副总裁GadiSinger更高层次的机器智能的核心,可能是让知识构建帮助人工智能系统组织自己的世界观,赋予人工智能理解意义、事件和任务的能力。如此一来,机器认知将从数据扩展到知识结构,包括描述性知识、世界动态模型和起源等维度。在学习语言时,我们要区分形式(form)和意义(meaning):形式指的是用来表达意义的符号,也就是表面的表达。每种形式在特定的语境中都有特定的含义,而形式在不同的语境中可以有不同的含义。正如Bengio和Schölkopf等人在“TowardsCausalRepresentationL

  • python json 编码(dump/dumps:字典转化为json)、解码(load/loads:json转化为字典)

    参考链接:pythonjson1-1:使用json.dump/dumps将JSON写入文件/字符串pythonjson编码(dump/dumps:字典转化为json)、解码(load/loads:json转化为字典) 一般接口传输数据的数据类型都是json,本文主要介绍json的编码、解码、读取等 1、json的数据类型(1)数字(int、float):     jsondata1=‘{“age”:18}’(2)字符串("")     jsondate2=‘{“phone”:“12345654321”}’(3)逻辑值(true/false)     jsondata3=‘{“boolValue”:False}’(4)null     jsondata4=‘{“nullValue”:None}’(5)对象({})     jsondata5=‘{“name”:“yezi”,“address”:{“country”:“china”,“city”:“HeBei”}}’(6)数组([])     jsondata6=‘{“updatedate”:[22,23,24]}’ 2

  • Python之并发请求(下)

    在Python之并发请求(上)中详细了介绍了使用多线程的方式来编写一个测试服务端程序的高并发请求的性能测试工具。在这个测试的工具中,依据高并发的请求之后,我们得到很全面的响应时间,吞吐量,错误率,以及其他的相关信息。在性能的测试中,更多的是CPU密集型和IO密集型的,基本很多服务端的程序都是基于IO密集型的,那么这样使用多线程的方式它的效率会更高。我们对前面的代码进行改造,既然我们已经可以很轻松的拿到了我们性能测试的结果信息数据,那么我们是否基于结合Flask-Restful的框架,把它提供成一个API,这样别人直接调用我们的API就可以测试被测试的服务端的程序了,这样的方式更加高效和简单。当然,这只是一种思想,在服务端的测试中,我们需要更多考虑的是服务在高并发下以及连续请求的前提下,是否会出现OOM以及SockedTimeOut以及TimeOut等其他的程序信息,如MQ的消息积压,服务的崩溃以及其他的异常情况。本文章这里就不详细的讨论服务的监控,关于saas化下服务的监控可以参考我的文章saas化架构中服务的监控实现思路和具体的代码。下面我们对具体的被测试的API进行封装,这里就以测

  • 有内味了!MIT文本转语音神器,少量数据集还原角色声音 | 在线免费

    十三发自凹非寺 量子位报道|公众号QbitAI文本转语音,又出了个神器。这个工具来自MIT,并且还是在线、免费,可以用它来生成各种字符的44.1kHz声音。这些声音是使用多种音频合成算法和定制的深层神经网络实时生成的。最惊艳的是,这个工具只需要少量的文本数据,还能保留文本所表达出来的韵律,可以说是相当的“声情并茂”了。使用起来非常简单,主页中的“Source”提供了几部电影或动画,“Character”提供了里面的一些角色。只需要在文本框中输入不多于140字符的文本,点击生成,就能很快输出对应角色、带有韵律的语音。文本转语音,有内味儿了效果怎么样?我们先来看看几个例子。首先是《Portal2》中的GLaDOS的声音。TheEnrichmentCenterwouldliketoannounceanewemployeeinitiative(inishutive)offorcedvoluntaryparticipation.IfanyApertureScienceemployeewouldliketooptoutofthisnewvoluntarytestingprogram,pleaser

  • python2和3的区别丶网络编程以及s

    一丶python2和python3的区别  1.编码&字符串    字符串:      python2:        Unicode    v= u"root" 本质上用unicode存储(万国码)        (str/bytes)   v="root" 本质用字节存储      python3:        str    v="root"    本质上用unicode存储(万国码)        bytes    v= b"root"    本质上用字节存储    编码:      python2:   ascii 文件头可以修改#-*- encoding:utf-8-*-      python3:   utf-8 文件头可以修改#-*- encoding:utf-8-*-  2.继承    python2:  经典类/新式类    python3:  新式类  3.范围    python2:   range/xrange    python3:   range  4.输入    py

  • teg Kafka的使用场景

    下面是一些关于Apachekafka流行的使用场景。这些领域的概述,可查看博客文章。消息kafka更好的替换传统的消息系统,消息系统被用于各种场景(解耦数据生产者,缓存未处理的消息,等),与大多数消息系统比较,kafka有更好的吞吐量,内置分区,副本和故障转移,这有利于处理大规模的消息。根据我们的经验,消息往往用于较低的吞吐量,但需要低的端到端延迟,并需要提供强大的耐用性的保证。在这一领域的kafka比得上传统的消息系统,如的ActiveMQ或RabbitMQ的。网站活动追踪kafka原本的使用场景:用户的活动追踪,网站的活动(网页游览,搜索或其他用户的操作信息)发布到不同的话题中心,这些消息可实时处理,实时监测,也可加载到Hadoop或离线处理数据仓库。每个用户页面视图都会产生非常高的量。指标kafka也常常用于监测数据。分布式应用程序生成的统计数据集中聚合。日志聚合许多人使用Kafka作为日志聚合解决方案的替代品。日志聚合通常从服务器中收集物理日志文件,并将它们放在中央位置(可能是文件服务器或HDFS)进行处理。Kafka抽象出文件的细节,并将日志或事件数据更清晰地抽象为消息流。这

  • Linux常用操作

    Redis相关:src/redis-serverredis.conf复制redis-clishutdown redis-cli-h127.0.0.1-p6379shutdown复制数据库相关:servicemysqlstart servicemysqlstop servicemysqlrestart servicemysqlstatus mysql-uroot-proot复制Tomcat相关:tomcatsystemctlstarttomcat tomcatsystemctlrestarttomcat tomcatsystemctldisabletomcat复制项目相关:java-jarboot.jar java-jarboot.jar& nohupjava-jarboot.jar&复制

  • 好一出大戏!绯闻缠身的Oculus未来会走向何方?

    近日,Facebook的虚拟现实部门OculusVR又惨遭诉讼了,吃瓜群众们对此事的态度已经由“我的天”变为“啊,又来了”。这次将Ocuuls告上法庭的苦主是一家位于加州的技术授权公司TechnoViewIPInc,该公司向联邦法院起诉Facebook和Oculus侵犯了VR头显制造商ImmersiON-VRelia拥有的3D成像专利。遥想当年,Facebook一掷千金拿出30亿美元收购了草根出身的Oculus。接下来几年,VR行业的迅速发展也证明Facebook的收购案确实是慧眼识英。而OculusRiftCV1和HTCVive在PCVR界的势均力敌,更是让Facebook对VR愈加看好。但是,Facebook与Oculus如今的处境其实并没有媒体所描述的那么一片坦途。官司缠身,Oculus究竟做了什么?Zenimax的CEORobertAltman 2014年5月,Facebook对外宣布将收购Oculus后的第三个月,Bethesda母公司Zenimax起诉旗下子公司idSoftware的创始人JohnCarmack从原公司盗取“关键技术”,并在OculusRift中使用了该技术

  • 数据分析:从PGONE事件中,你们看到了人性,我却看到了明星真实的粉丝数据

    明星的微博粉丝数量一直都是个谜,原因在于无论有多少人质疑明星在微博买粉丝数量,但是苦于一直没有证据,所以也就只是大家知道,粉丝不认而已,这也就是成谜了。备注:我要向我微博为数不多的粉丝先声明,我不追任何一个明星,今天为了采集数据,无意中点赞了一个明星微博,请告诉我,微博可以取消赞吗?但是我觉得这次的李小璐夜宿事件似乎提供了真是了解微博明星流量的机会,因为这次是全民大事件,其真正的粉丝不可能不知道,为了维护所谓偶像,极大可能性会参与其中,有兴趣可以去看看这粉丝怼天怼地怼父母、共青团、新华社、紫光阁、央视的架势和气势,就会知道他们有多积极参与其中了。另外一个分析核心是,在经过几大超级微博大v,例如共青团、新华社、紫光阁、央视批评之后,大部分水军(重点)已经意识到再也洗不白了,也就放弃了洗白,剩下的就是粉丝数量了。我就以事件中的所谓的嘻哈男猪脚微博为例,由于我实在不想打下那个名字,为了省事,我就以SB为代号吧。我们首先来看,这SB货在微博上显示的粉丝数量是476万,当然,这粉丝数量在明星当中也只能算是中规中矩,但是这真的是真是数据吗?接下来看,下图是该微博1月4日发布的微博分布在2018年1

  • bytebuf池_Netty ByteBuf[通俗易懂]

    大家好,又见面了,我是你们的朋友全栈君。ByteBufByteBuf需要提供JDKByteBuffer的功能(包含且不限于),主要有以下几类基本功能:7种Java基础类型、byte[]、ByteBuffer(ByteBuf)的等的读写缓冲区自身的copy和slice设置网络字节序构造缓冲区实例操作位置指针扩容原理首先确认ByteBuf是否已经被释放,如果被释放,则抛出IllegalReferenceCountException异常判断写入需要的最小空间,如果该空间小于ByteBuf的可写入空间,直接返回,不进行扩容判断写入需要的最小空间,如果该空间大于ByteBuf的(最大容量-当前的写索引),不进行扩容,抛出IndexOutOfBoundsException异常计算新容量,动态扩容的规则,当新容量大于4MB时,以4MB的方式递增扩容,在小于4MB时,从64字节开始倍增(Double)扩容读写索引Netty提供readIndex和writeIndex用来支持读取和写入操作,两个索引将缓冲区划分为三个区域0~readIndex:已读区域(可丢弃区域)readIndex~writeInde

  • Ingress Nginx v0.30 Hostnetwork高性能模式安装

    IngressNginxv0.30Hostnetwork模式安装 apiVersion:v1 kind:Namespace metadata: name:ingress-nginx labels: app.kubernetes.io/name:ingress-nginx app.kubernetes.io/part-of:ingress-nginx --- kind:ConfigMap apiVersion:v1 data: large-client-header-buffers:41024k proxy-body-size:250m client-header-buffer-size:512k client-body-buffer-size:2048k compute-full-forwarded-for:'true' use-forwarded-headers:'true' forwarded-for-header:"X-Forwarded-For" keep-alive-requests:"10000" max-worker-connections:"65536" log-f

  • Java中静态变量与非静态变量的区别

     ①java类的成员变量有俩种:         一种是被static关键字修饰的变量,叫类变量或者静态变量         另一种没有static修饰,为成员变量       ②通俗点说:         类的静态变量在内存中只有一个,java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享。静态变量可以直接通过类名进行访问,其生命周期取决于类的生命周期。         而实例变量取决于类的实例。每创建一个实例,java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中,其生命周期取决于实例的生命周期。   注意点:     

  • NTP 解析

    1. 202.107.6.88 220230E70000031300000044646B1972E6BAE003507991F43030303030303030E6BAE02AFBB4D198E6BAE02AFBB57931 【Hex】 LI[2bits],VN[3bits],Mode[3bits],Statum[8bits],Poll[8bits],Precision[8bits] RootDelay RootDispersion ReferenceIdentifier ReferenceTimestamp OriginateTimestamp ReceiveTimestamp TransmitTimestamp 根延时 根描述 参考标志 T3参考时间戳 T0起源时间戳[请求时的T2] T1接收时间戳 T2 传输时间戳 0123456789101112131415161718192021222324252627282930313233343536373839 4041424344454647 220230E7 0

  • 水晶报表布署总结(转载)

    本文转载自:http://www.tuicool.com/articles/Jb6ziyJ   这两天搞安装包真心坎坷,一个问题接一个问题,先是为了实现自定义动作现啃vbs,后面又是安装过程老是报错: 各种搜索、各种尝试,总算搞掂,积累了些经验,分享一下。 首先CRforVS2010的所有东东都在这里:http://scn.sap.com/docs/DOC-7824 简单说一说资源下载表的情况,资源表如图(敢情都出到SP10了,我用的是13.0.9.1312): 每列代表一类资源,每行代表一个版本,我仅就我知道的资源类别介绍一下: InstallExecutable:我理解是完整版,包括VS插件、报表设计器、运行环境等所有东西,装上后就可以在VS中创建CR报表了。适用于开发机; MSI32/64Bit:运行环境独立安装包,分别适用于32/64平台。就是装在客户电脑上的东东,下文我所谓的MSI整合法就是指这个; MSM32Bit:也是运行环境,只不过是用来合并在安装包中的,不能独立安装。看起来只有32位版;下文我所谓的MSM合并法就指它 别的什么ClickOnce、WEBX

  • Mysql和Redis数据同步策略

    目录为什么对缓存只删除不更新先更新数据库还是先删除缓存?CacheAsidePatternDouble-DeleteRead/WriteThroughPatternWriteBehind设置缓存过期时间总结 为什么对缓存只删除不更新 不更新缓存是防止并发更新导致的数据不一致。 所以为了降低数据不一致的概率,不应该更新缓存,而是直接将其删除, 然后等待下次发生cachemiss时再把数据库中的数据同步到缓存。 先更新数据库还是先删除缓存? 有两个选择: 1.先删除缓存,再更新数据库 2.先更新数据库,再删除缓存 如果先删除缓存,有一个明显的逻辑错误:考虑两个并发操作,线程A删除缓存后,线程B读该数据时会发生CacheMiss,然后从数据库中读出该数据并同步到缓存中,此时线程A更新了数据库。 结果导致,缓存中是老数据,数据库中是新数据,并且之后的读操作都会直接读取缓存中的脏数据。(直到key过期被删除或者被LRU策略踢出) 如果数据库更新成功后,再删除缓存,就不会有上面这个问题。 可能是由于数据库优先,第二种方式也被称为CacheAsidePattern。 CacheAsidePatter

  • 小记

    1.hust上面两套树形DP 2.hust上面两套区间DP 3.学习哈希,巩固kmp,多刷几道熟悉 4.刷hdu上面DynamicProgramming专题以及search专题 5.学习二分图,网络流(√ ×) 6.看大白书,把入门经典小白书例题刷一遍 7.orz不知道什么时候能否刷完~~想到什么了再补充,在这学期结束之前尽量结束~~ 8.容斥原理

  • [朝花夕拾] LeetCode每日一题

    值得一提: 202203042104;20220309798;202203301606;   202202281601. 最多可达成的换楼请求数目 方法一:DFS枚举 枚举所有换楼请求的选择与不选择两种情况,最后判断是否满足题意,时间复杂度为O(2^m),m为请求个数,依题意m<=16,符合要求。 1#include<cstring> 2 3constintN=25; 4 5classSolution{ 6public: 7inta[N][N],b[N]; 8intdfs(into,intx,intn,intm){ 9intres=0; 10if(o==m){ 11inttot=0; 12for(inti=0;i<n;i++){ 13for(intj=0;j<m;j++) 14tot+=(b[j]?a[j][i]:0); 15if(tot!=0)return0; 16} 17returnx; 18} 19b[o]=1; 20res=dfs(o+1,x+1,n,m); 21b[o]=0; 22res=max(res,dfs(o+1,x,

  • GAMES101作业解答-作业02-Triangles and Z-buffering

    GAMES101作业解答-作业02-TrianglesandZ-buffering 1.题目要求 在屏幕上画出一个实心三角形,换言之,栅格化一个三角形。上一次作业中,在视口变化之后,我们调用了函数rasterize_wireframe(constTriangle&t)。但这一次,你需要自己填写并调用函数rasterize_triangle(constTriangle&t)。 该函数的内部工作流程如下: 创建三角形的2维boundingbox。 遍历此boundingbox内的所有像素(使用其整数索引)。然后,使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。 如果在内部,则将其位置处的插值深度值(interpolateddepthvalue)与深度缓冲区(depthbuffer)中的相应值进行比较。 如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区(depthbuffer)。 我们需要修改的函数如下: •rasterize_triangle():执行三角形栅格化算法 •staticboolinsideTriangle():测试点是否

  • 怎么卸载Navisworks Manage ?如何把Navisworks Manage彻底卸载删除干净重新安装的方法【转载】

    NavisworksManage卸载工具,完全彻底删除干净NavisworksManage各种残留注册表和文件。NavisworksManage安装失败,怎么完全彻底删除清理干净NavisworksManage各种残留注册表和文件呢?有些同学想把NavisworksManage重新安装,但是NavisworksManage安装失败显示失败,有时NavisworksManage安装到一半就显示失败,然后会问NavisworksManage无法重装是怎么回事。那么NavisworksManage安装失败的原因是什么呢?如何才能把NavisworksManage卸载干净呢?有人说只要把NavisworksManage注册表7d2f删除就可以了,但是有的同学找到了NavisworksManage注册表7d2f也删除了,但是NavisworksManage再次安装失败。还有的同学直接重装系统,但是重装系统后NavisworksManage仍然无法安装。还有的同学直接把NavisworksManage的程序文件删除,重装NavisworksManage的时候会显示已安装。那么NavisworksM

  • Retrofit实现PUT网络请求,并修改Content-Type

    @FormUrlEncoded @PUT(Constant.BOSS_HX_CHANGE_PHONE_INTERVIEW) Call<ResponseHxResultBean>handleInterview(@Field("user_id")Stringuser_id,@Field("token")Stringtoken,@Field("id")Stringid,@Field("status")intstatus,@Field("inter_id")Stringinter_id,@Field("schedule_id")Stringschedule_id); }复制 网络请求的接口如下所示,其实与POST请求基本相同只是将注解@POST还成了@PUT至于需要修好的Content-Type网上查询资料可以添加注解@Headers(静态请求头) 其他请求的部分就正常写就行了。

  • java实现一个简单的计数器

    packagecom.fengunion.sf;importorg.junit.platform.commons.util.StringUtils;importjava.util.HashMap;importjava.util.Map;importjava.util.Random;publicclassCountUtil{privatestaticMap<String,Integer>map=null;static{map=newHashMap<String,Integer>();}/****实现一个简单的计数器*@paramstr*@return*/publicstaticintcountNum(Stringstr){if(StringUtils.isNotBlank(str)){Integercount=map.get(str);if(count==null){count=1;}else{count++;}map.put(str,count);}returnmap.get(str);}publicstaticvoidmain(String[]args){fo

相关推荐

推荐阅读