当前位置: 首页 > 编程日记 > 正文

dogse入门指南

dogse入门指南

Dogse作为游戏服务端引擎,目前只包含游戏服务端的核心部分,但这也是最核心的部分。它全部使用.net c#开发,充分兼顾了程序性能与代码编写的准确性与易用性,再加上以vs作为开发工具,极大的提升代码的编写效率,以及方便的调试性。

在使用Dogse之前,我们还需要先了解它能做什么,在游戏服务端里处于什么位置。

Dogse简单的说,实现了游戏服务器的基本框架,包含最基础的网络通讯,消息协议,任务调度等基本的功能。和业务逻辑相关的代码都不包含在dogse里,还需要使用者自己来编写。

我们以demo 《TradeAge》为例子,说说一个基本的游戏项目的划分方式。

重要事情说3遍,dogse下载地址:

https://github.com/dogvane/DogSE

https://github.com/dogvane/DogSE

https://github.com/dogvane/DogSE

 

项目基本结构

 

服务器端结构

首先整个服务端可以划分为以下几个项目

 

TradeAge.Server.Entity 实体类项目是游戏里用到的各种数据对象,包括玩家的游戏数据,游戏的配置数据,以及一些服务器存储数据

TradeAge.Server.Interface 接口类定义的则是服务器与客户端的交互接口,客户端对服务器的一些收发数据的格式内容定义在这里,它依赖实体类项目

TradeAge.Server.Protocol 通讯协议项目,这个项目里保存的是对接口类项目的通讯交互协议的实现,这个项目里的代码是通过代码生成器来生成的,一般不需要手工去修改他。

TradeAge.Server.Logic 整个游戏的业务逻辑都写在这个项目里,具体的一些编写规则会后面描述

TradeAge.Server.Game 是整个游戏的启动项目,可以是控制台,可以是nt服务,或者是winform窗体。在这里完成一些简单的初始化工作就ok了。

基本上来说,整个游戏服务端的项目可以按照整个模块划分,当然根据项目类型的不同,也可以自己根据需要去修改项目的模块划分结构,只不过对于小项目而言,可以从整个结构开始了解整个服务器开发的过程。

 

 

客户端结构

客户端部分可以先分为以下几个部分

 

TradeAge.Client.Entity 客户端的实体类,基本与服务器项目里的 TradeAge.Server.Entity 里的文件保持一致,甚至可以共用一份文件,通过一些项目配置来对实体数据根据客户度和服务端做一些差异化的配置,这部分后面会详细说

TradeAge.Client.Controller 客户端的控制器,传说中的mvc杀器,在负责和游戏服务端对接,大部分的代码是自动生成的,视图层通过这个模块公开的事件(.net的event事件)来获得服务器对客户端的请求操作,并通过这里的一些方法来向服务器发起操作请求。

TradeAge.Client.Simulator 客户端模拟器,可以方便的不启动Unity3D等客户端情况下测试游戏里的某个功能。后期还可完成压力测试的机器人。

 

登陆模块实战

 

有了基本结构后,我们先来补充一下所有游戏都会用到的基本功能(登陆模块),并以这个功能来详细描述如何使用dogse构建一个游戏。

 

对象定义

 

首先为了实现登陆,必须有一个账号类,记录里登陆玩家的账号名与密码(如果是第三方平台接入,或者单点登陆,除了账号外,还会有一些其他的内容,具体情况根据实际碰到的问题在做增减)。

账号对象只对应着平台登陆,通常是放在Mysql里,demo里为了减少对系统的依赖,则放在一个xml文件系统里。

客户端在向服务器发起登陆请求后,服务器应该返回这次的登陆结果(成功或者失败)。如果成功成功,则还需要返回玩家在服务器里是否创建过角色,客户端再根据这个返回信息决定,是直接进入游戏,还是打开创建角色界面。当然,这个是目前页游和手游常见的做法,对于mmo网游,通常返回的就是一个玩家列表,一个账号在一个服务器里存在多个游戏角色。

 

 

我们先将账号类Account和玩家的角色类Player定义好放在TradeAge.Server.Entity项目下。

 

接口定义

 

对象定义好了,我们接着看一下客户端与服务器是如何交互的。

最开始描述功能的时候,说了,对于一个登陆模块来说,我们用一个简单的序列图来描述整个登陆流程

序列图很简单吧,实际在dogse里定义这个交互过程也很简单。

我们在TradeAge.Server.Interface项目里增加两个目录

 

Client放的是服务器给客户端发数据(消息)的接口

Server 放的是客户端给服务器发送数据(消息)的接口

当然,目录不是强制的,你们想怎么定义都行。

 

服务器接口定义

Server目录下,增加第一个服务器登陆模块的接口文件ILogin

 

 

打开文件加入以下代码

 

大家可以注意看一下标注的几个地方。

1.服务器的接口需要继承自ILogicModule

2.每个网络消息对应一个接口的方法(类型wcf,webservice的接口定义)

3.每个方法上面需要有一个NetMethodAttribute的属性,并填写上正确的参数

 

ILogicModule接口

 

这是Dogse里,对于每一个服务端的业务逻辑模块必须要实现的接口,包含一个属性,四个方法。这四个方法都会在整个游戏的生命周期里的不同时段被调用。大家可以在里面做一些必要的初始化。

 

接口里的消息方法

 

再看看每个消息方法

 

 

Dogse之前使用mmose的时候,每个消息的处理函数都是这样定义的

 

在业务逻辑代码里再对这个reader里的数据做解析(参考Dogse\Example4和 Dgose\Example5)。

现在Dogse只要将通信的数据写在每个方法里就能自动生成通讯协议代码,当然一些必要的约束还是要有的

1.方法的第一个参数必须是NetState类型,这个是用来表示是那个客户端接入服务端的。

2.方法允许空参数,方法实际上还是得有NetState这一个参数。

3.参数的基本类型有:int  long  byte  float  double  bool  string  DateTime(DateTime实际按照long类型传输,取值DateTime.Ticks

4.参数运行数组与List<T>类型

5.参数运行对象,但对象里的属性也只能是基本类型,数组与对象


方法的定义就这些要求,接下来再说说方法的属性标签

 

 

消息码

消息码作为前后通讯的唯一标识,大家应该都可以理解了,dogseushort类型(双字节)在实际项目里,可以定义一个枚举在记录通讯的消息id

 

 

一般来说,ushort最大长度是65535,对于一般的游戏绝对够用了,当然,你还有什么特殊的做法或者想法,那就需要自己扩展了。

 

 

方法类型

 

这个看注解基本可以了解,

PackaetReader需要自己来解析数据,适合当你有非常复杂的数据结构时使用,偶尔为之即可,不可常用。

SimpleMethod Dogse建议的方法,基本可以满足需求

ProtocolStruct 当初设计的目标是让.net下的结构体和c\c++下的结构体数据在字节上做序列化,不过不建议使用,除非你真的能保证内存结构的一致性

 

是否进行登录验证:

这是一个很神奇的参数,一般默认都是true,他可以在读写数据包操作前,对这个包做一个简单的过滤。简单的说,执行这个方法的客户端必须在完成登陆操作后才能被执行到。如何验证在今后的登陆模块里会说到。

当然,在Login的方法里,这个值必须是false

 

任务类型:

今后在说Dogse底层的时候会详细的说明。

 

客户端接口定义

服务端的接口说完了,我们来看看客户端的接口

 

这里有2个类,一个是ILogin,和之前的服务端的ILogin类一样,里面写了和登陆相关的接口。ClientProxy顾名思义,就是客户端代理类,也就是服务器如果要往客户端发送数据,则需要通过这个类来发送

先看看ILogin的设计:

 

接口文件和服务端接口文件类似,只不过客户端的接口没有继承自ILogicModule,而是给接口加了ClientInterface的属性标签。这个标签的作用也仅仅是说明这个接口是为了服务器往客户端发送用的。剩下的方法与方法上的属性标签和服务器定义的需求一致。

 

 

ClientProxy则是对客户端接口模块做一个汇总的静态类,方便服务器找到对应的接口来发送数据。

 

消息代理类以及代理类生成工具

 

TradeAge.Server.Interface 的项目就介绍到这来,下面开始dogse的黑科技部分--代理类生成。

打开DogSE.Tools.CodeGeneration项目下的Program.cs文件

 

我们可以看到这个方法,他的作用就是将TradeAge.Server.Interface项目里的接口,生成2个代理类到TradeAge.Server.Protocol 项目的目录下,文件名分别是ServerLogicProtocol.csClientProxyProtocol.cs。在最开始的时候,dogse也采用这样的代码生成技术,只不过是可以在服务器启动的时候就自动生成,并在内存里完成编译。但是这样的代码非常不利于debug,所以最后还是决定生成到文件里。当然,最终文件的输出路径(项目)和文件名都是可以换的,只不过我个人觉得,还是有一个独立的项目来放这些自动生成的代码会比较好。

 

让我们来看一下这两个类分别干了什么事情

 

ServerLogicProtocal.cs

 

ILoginAccess1这个是对ILogin这个接口的包装,注意,是包装,不是实现。

它的作用是承上启下,从Dogse的网络层获得消息包事件,然后再转发给逻辑模块里的对应方法。

 

这个方法就是用来绑定ILogin接口所对应个的逻辑模块实例

 

这个方法则是向Dogse注册和登陆相关的消息id所绑定的方法

 

 

 

而这两个方法这是用来解析消息包,并调用对应的游戏业务逻辑方法。

 

而整个游戏所有的业务接口类的包装类,都在这个方法进行统一的注册,到时候在程序启动的时候,只需要这样

 

一调用,服务器这个小伙伴就可以愉快的玩耍了。

 

当然这个类里的东西,大家基本上了解他是干啥的就行了,除非你不打算使用目前Dogse这套对数据进行序列化/反序化的方法可以,先对这里的代码做修改,然后形成一套规则,再修改DogSE.Tools.CodeGeneration 项目里的代码生成器。今后有空应该会补上protobuf的处理方法。

 

ClientProxyProtocol.cs

 

有了对服务器端的了解,客户端代理类就更简单一些了,基本上就是对方法参数做序列化后,转为消息包的格式通过Netstate暴露出来的方法把数据发送给客户端。

 

服务器端逻辑处理

 

有了底层的了解,我们来瞅瞅服务器最关键的部分,TradeAge.Server.Logic项目的结构

 

和之前的服务器端接口文件定义一样,一个接口文件对应一个业务模块,每个业务模块可以在这里就会对应一个对这个接口的实现类

 

 

这个是登陆模块的基本代码,我们先从接口方法到初始化方法过一次。

 

登陆的第一步自然是根据账号名去数据库里查玩家的账号在不在,在就验证密码,不在则创建一个新账号。这里说一下,为了演示,我没有做服务器连接,而是将数据保存到本地的xml文件里,一个账号对一根文件。实际项目应该是根据实际的场景连接对应的数据库,要么是mysql,要么是mongodb

 

账号通过验证,做一些数据的基础赋值

 

注意这个操作,这里需要将netstate里的IsVerifyLogin的属性设置为true,说明,这个客户端连接通过了登陆验证,今后这个客户端再发过来的各种数据包才能触发对应的服务器方法。

 

没错,就是之前的ServerLogicProtocol.cs里的方法,在这里对网络连接预先做了判断,如果没有完成登陆,是不会触发服务器的创建角色方法。

基本属性设置好了,接着就是从数据库里加载与账号对应的角色数据。

这里做了一个判断,先读内存里的缓存数据,再读数据库,如果数据库里也没数据,则说明这个账号没创建过角色,那么返回给客户端的登陆成功消息里,是否创建角色的参数就只能是false,让客户端先创建角色才能继续下面的游戏。

 

这里就是当玩家创建过角色后,进行一些判断,第一步,先看看这个角色之前是否已经登录过,并且现在还在线。

这里的 player 对象在上面是先从缓存里读,再从db里读,如果玩家之前在线,那么缓存里一定会有这个玩家对象,同时和这个玩家所绑定的NetState的就是一个有效的对象,只需要判断这个对象在不在就知道此刻有没有另外一个客户端正在连接服务器,我们需要做的也仅仅是把这个客户端断开。(实际的项目里,还需要向客户端补发一条消息,告诉玩家你被其它地方登陆的客户端顶下线了)

接下来就是让 player对象和 netstate 对象互相关联起来。

 

PlayerEnterGame独立出一个方法来,主要是为了让OnCreatePlayer里当玩家创建角色后,走同一套进入游戏的流程,目前这个方法只有2个函数,但随着项目的演进,这个方法会越来越膨胀的。

 

触发玩家事件

 

PlayerEvents则是另外另外一种初始化玩家进入游戏的方法,这个今后在各种模块里会详细跟大家说明的。这里简单的说一下,就是一些公共事件,例如登陆,离线,升级,解锁啥的,一些模块可能都需要在那个时刻做一些与自己相关的处理,这时候,如果都写在Login模块里的PlayerEnterGame里,会让代码在今后维护起来相当麻烦,所以,可以在游戏里设计一个静态的PlayerEvents的事件类,凡是有模块需要在登陆时做一些自己的特殊处理的时候,监听这个事件,然后模块自己的初始化代码就放在自己的模块里了。

关于登录的函数就说完了,剩下还有一个创建角色的代码,大家可以自己看看,基本逻辑和登录差不多。

 

服务器启动代码

 

底层的模块好了,我们下一步是让服务器端跑起来。

 

TradeAge.Server.Game项目就是用来启动服务端的程序,只所以要另外建立一个exe的宿主项目,是为了今后扩展用(动态更新服务端)。

 

 

这里的ServerConfig 对象是服务器连接用的,这里是示例代码,所以在这里初始化,实际项目里,应该是需要从本地的配置文件里读取的,这部分今后会详细介绍。

Logs dogse的日志模块,这里初始化了文件和控制台的日志

GameServerService 是整个服务器的一个总控,用于控制整个服务器的初始化流程,以及服务器状态的维护。一般来说服务器的初始化流程,先完服务配置文件的初始化,再完成游戏配置文件的初始化,接着初始化游戏模块,等游戏模块初始化完成后,就可以开启服务端socket接入客户端的连接请求了。目前项目是控制台程序,那么服务器启动好以后,需要接收管理员在控制台的一些指令输入(如退出,查询状态,重新加载某些数据等)。如果管理员在控制台输入了exit后,整个游戏会进入退出流程,先关闭客户端的连接,然后等待数据保存到数据库,最后才关闭整个进程。这些流程上的功能都是GameServerService进行控制的。

WorldBase 是游戏世界的实例,这部分和GameServerService一样,属于dogse的底层部分,这里我们简单的可以认为WorldBase就是控制着游戏运行逻辑的模块,它负责开启网络连接,客户端socket过来的网络消息,会转换为一个个网络任务,然后通知到对应业务逻辑处理代码。理论上说,一个服务端里可以开启多个游戏世界的实例,但目前来说还没这样做,更多的时候是开启多个游戏进程。

 

这里说一下,当游戏业务逻辑模块初始化完成后(所有继承自ILogicModule接口的对象的Initializationed方法被执行过)会触发GameServerServiceAfterModuleInit的事件,这个时候,我们需要向系统注册模块的处理函数,和客户端代理类的注册。今后加入动态更新功能的话,在新的逻辑模块加载完成后,对新的逻辑模块重新注册后,就可以将客户端的操作请求切换到新的代码里了。

 

客户端部分解析

生成代理类

 

Dogse在生成服务器代理类的同时,针对u3d客户端,也会生成对应的接口的协议代码,最大程度上方便客户端的开发,生成方法类似服务器的生成方式。

 

客户端部分的代理类生成和服务器差不多,只不过这次不想服务器端那样,指定一个文件了,而是指定一个目录。我们再看看终客户端通过代码生成器生成的目录结构:

 

首先是LogicInterface.cs

 

客户端业务逻辑

 

这个是TradeAge.Server.Interface项目下Client目录下服务器往客户端发送数据的接口生成的代码,基本上是将接口的第一个Netstate参数移除后生成生成的。这里没有采用Interface而是抽象类作为客户端的接口,主要目的是让非TradeAge.Client.Contrller模块,也就是Unity3d,模拟器的项目在使用该模块模块的时候,不要看到这些由网络消息触发的方法。

 

和服务端一样,会生成2个协议代理文件客户端也会按照模块分别生成文件名为“模块.Net.cs”和“模块.Proxy.cs”文件,这分别是服务器通知客户端触发代码(.Net.cs),以及客户端向服务器通知的代码(.Proxy.cs),而我们还需要另外自己新建一个文件“模块.Logic.cs(名字可以随意起,这个不做命名要求)。

模块.Logic.cs

 

控制器的名字为TradeAge.Server.Interface项目里对应个的IModule 接口的名字+Controller组成,这个是固定的,类必须继承自客户端LogicInterface.cs文件里定义的“Base模块Controller”命名的抽象类。完成定义后,就会想集成Interface一样,会要求你补完哪些响应网络消息的函数。今后客户端控制器的重点就在这个模块里了。我们需要在这里,将网络过来的消息,进行一些适度的包装,再通过事件的方式让View层知道有怎样的消息过来了。这部分代码

最后就是在GameController.cs文件里,把刚才的登陆模块加到里面。

 

这样客户端的Controller模块就算基本完成了,剩下的就是view层的事情了,在还view层还没开始做之前,我们先来做一个登陆模拟器。

 

登陆模拟器

 

 

BaseLoginTest.cs是我们的第一个客户端模拟器,完成了登录游戏,并创建第一个角色的功能。

 

一开始监听了3个事件,分别是网络连接,登陆完成,创建角色完成。接着你们就启动服务端,并让客户端连接到服务器

 

如果连接成功,则向服务器发送登陆请求。

 

登陆成功了,则看看角色是否创建过,没有的话就向服务器发送创建角色的请求。

 

好了,到这来登陆测试代码就算完成了。

最后,回到模拟器的程序的Program.cs处完成启动代码

 

这个代码就比较简单了,今后如果有啥移动测试的代码,可以再新建一个类,去做移动的数据包发送,更高级的还有战斗啥的,到时候在这里替换BaseLoginTest的对象就可以了。

整个TradeAge的登陆Demo介绍就到这里结束了。让我们把客户端和服务器都跑来器看看吧。

 

 



来自为知笔记(Wiz)



转载于:https://www.cnblogs.com/yahle/p/5125521.html

相关文章:

Python maketrans() 方法

描述 Python maketrans() 方法用于给 translate() 方法创建字符映射转换表。 可以只接受一个参数&#xff0c;此时这个参数是个字典类型&#xff08;暂不研究这种情况&#xff09;。 对于接受两个参数的最简单的调用方式&#xff0c;第一个参数是字符串&#xff0c;表示需要转换…

二:serverless网站数据库操作

操作数据库API文档 第一篇&#xff0c;搭建一套免费的serverless网站 一&#xff0c;创建集合&#xff0c;进入控制台 登录腾讯云后台 打开云开发控制台 可以新建集合&#xff0c;新建集合后点击集合名称即可批量导入导出数据库集合的数据&#xff0c;还可以设置数据库访问的…

我希望支持JavaScript GraphQL实现的API

The GraphQL schema language is great! It is certainly the best way to communicate anything about a GraphQL service. No wonder all documentations now use it!GraphQL 模式语言很棒&#xff01; 当然&#xff0c;这是传达与GraphQL服务有关的任何东西的最佳方法。 难怪…

2_Selenium对象识别

1 准备工作 firebug和firepath我们使用xpath进行元素定位&#xff0c;所以需要安装firefox的两个插件&#xff0c;帮助编写xpath html知识在编写xpath的时候&#xff0c;需要查看html代码&#xff0c;所以需要理解html知识&#xff0c;可以到http://www.w3school.com.cn/去自学…

Mac OS Terminal Commands

转自 &#xff1a; http://www.renfei.org/blog/mac-os-x-terminal-101.html Mac OS X Terminal 101&#xff1a;终端使用初级教程 July 29, 2012 / 编程指南最近学习苹果认证的《Mac OS X Support Essentials》教程&#xff0c;看到 Command Line 一节有很多实用的知识&#x…

封装一个计时器,记录页面的停留时间

在页面加载时初始化计时器&#xff0c;页面结束时取值。 效果如图&#xff1a; 下面是uniapp的代码示例&#xff1a; <template><view class"aaaacc"><view class"aaa">{{time}}</view></view> </template><scri…

ess用户名和密码_陈ess洁如何从摄影系学生转变为成功的自由职业者和内容创作者(播客)...

ess用户名和密码This week, for our last podcast episode of 2019, I got to chat with freelancer and content creator Jessica Chan - known as CoderCoder on social media - about how she got into tech and started her educational website and YouTube channel.本周&…

安装wxpython——python程序GUI图形界面使用

一、本机使用python版本 1、本机使用python版本为3.6.2&#xff0c;windows系统。 二、安装步骤 1、开始-运行-cmd 2、python3.x 需要进入python安装位置下是pip目录&#xff0c;再执行pip 命令 其中&#xff1a;python F:\Users\Administrator\AppData\Local\Programs\Python\…

ASP.NET全球化与本地化 c#多国语言的支持 (项目支持多国语言的开发)

ASP.NET 2.0及以上的开发平台&#xff0c;为全球化本地化应用程序提供了工具&#xff0c;而且实现起来非常简单。以下内容是使用c#&#xff0c;按照帮助一步步做的&#xff0c;将为初学者提供详细的实现步骤。 一 几个必要概念 &#xff08;一&#xff09; 支持全球化  由于…

promise 和 async await区别

什么是Async/Await? async/await是写异步代码的新方式&#xff0c;以前的方法有回调函数和Promise。   async/await是基于Promise实现的&#xff0c;它不能用于普通的回调函数。   async/await与Promise一样&#xff0c;是非阻塞的。   async/await使得异步代码看起来像…

mac 制作usb启动盘_如何使用Mac制作Windows 10 USB-从Mac终端构建可启动的ISO

mac 制作usb启动盘Most new PCs dont come with DVD drives anymore. So it can be a pain to install Windows on a new computer.大多数新PC不再附带DVD驱动器。 因此&#xff0c;在新计算机上安装Windows可能会很痛苦。 Luckily, Microsoft makes a tool that you can use …

作业05-继承、多态、抽象类与接口

1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 接口&#xff0c;Comparable&#xff0c;Comparator 1.2 尝试使用思维导图将这些关键词组织起来。 1.3 可选&#xff1a;使用常规方法总结其他上课内容。 1.接口特点&#xff1a;一个公开的界面 有统一定义的规…

炫彩流光按钮 html+css

话不多&#xff0c;先上效果&#xff1a; 简介&#xff1a; 用基础css做一个有一点炫酷的流光按钮&#xff0c;不止按钮&#xff0c;只要是盒子就行。 具体步骤&#xff1a; 1.先定义一个盒子当做按钮&#xff0c;如我就用a标签&#xff1a; <body><a href"#…

SQL取上一条, 下一条记录方法

如果我们需要取id为3的前后的1条记录. 就可以用以下方法 取上一条记录: select * from 表名 where id<3 order by id desc limit 1取下一条记录: select * from 表名 where id>3 order by id asc limit 1大小于比较 order limit 转载于:https://www.cnblogs.com/…

react中使用构建缓存_通过构建海滩度假胜地网站,了解如何使用React,Contentful和Netlify...

react中使用构建缓存In this full course from John Smilga you will learn React by building a beach resort website project. The project uses React router for routing, React context API for state management, Contentful headless CMS for data management, and Net…

R语言实战 - 基本统计分析(2)- 频数表和列联表

数据&#xff1a; > library(vcd) > head(Arthritis)ID Treatment Sex Age Improved 1 57 Treated Male 27 Some 2 46 Treated Male 29 None 3 77 Treated Male 30 None 4 17 Treated Male 32 Marked 5 36 Treated Male 46 Marked 6 23 …

随机位置显示图片不重叠前端实现详细讲解附效果图,代码可直接使用

目录先看看效果图所要实现的功能看看代码js代码讲解&#xff1a;下面看看完整代码吧小程序版本完整代码VUE版本的代码&#xff1a;先看看效果图 所要实现的功能 在页面上随机的位置显示随机大小的图片&#xff0c;并且每个图片不能重叠&#xff0c;完整实现代码。 看看代码 …

MVC缓存OutPutCache学习笔记 (一) 参数配置

OutPutCache 参数详解 Duration : 缓存时间&#xff0c;以秒为单位&#xff0c;这个除非你的LocationNone&#xff0c;可以不添加此属性&#xff0c;其余时候都是必须的。 Location : 缓存放置的位置; 该值为枚举值: None: 当被设置为None时&#xff0c;其余的任何设置将不起作…

在Mac上控制Alt Delete-如何在Macbook上打开任务管理器

It happens to the best of us: were working away on some important project, and our trusty computer freezes. Or rather, a program were in just stops responding. So what do you do?这对我们最好的人来说是偶然的&#xff1a;我们正在做一些重要的项目&#xff0c;而…

HEW MAP文件使用

参考资料转载于:https://www.cnblogs.com/iluzhiyong/p/5145396.html

算法导论九章 答案

http://blog.csdn.net/z84616995z/article/details/18840823?reload 9.3-8题&#xff1a; http://blog.csdn.net/z84616995z/article/details/18938181 9.3-9题&#xff1a; http://blog.csdn.net/z84616995z/article/details/18889535转载于:https://www.cnblogs.com/sa51718…

小程序实现瀑布流,获取图片高度分成两组数据的函数封装代码

把一个数组根据数组内部的图片的高度&#xff0c;拆分成两个数组&#xff0c;组成瀑布流数据的方法。 使用方式&#xff1a; async created() {var arr this.$mock.sssdata.data.lists;//arr 是一个数组&#xff0c;里面包含若干对象&#xff0c;对象里面有图片var myArr a…

实现线程哪种方法更好_实施数据以实现更好的用户体验设计的4种方法

实现线程哪种方法更好Gone are the days when design used to rely mainly on the color palettes and the creativity of the designer. In the rapidly expanding technological world of today, it is essential to work across departments to enhance the screen experien…

String比较.equals

首先定义四个变量str public class SIzhui {public static void main(String[] args) {String str1"wang";String str2"li";String str3"wang";String str4new String("wang");} } 然后进行比较 public class SIzhui {public static …

mac下mysql5.7.10密码问题

mysql5.7.10刚安装好&#xff0c;会生成一个随机密码。 如果没记住这个随机密码&#xff0c;那么到mysql/bin/下执行mysql_secure_installation命令 按照提示重置密码和其他选项。 ps&#xff1a;找了一下午终于找到方法了&#xff01;&#xff01;&#xff01; 转载于:https:/…

Error: Cannot find module ‘express‘

解决方案&#xff1a;把node_module整个文件夹删掉,然后npm clean cache,看下package.json里有没有express的依赖项,有的话直接npm install,没有的话 npm install express --save

Observables简介以及它们与Promise有何不同

‘Observables’, ‘Observables’, ‘Observables’...Yes! Today, we will talk about this often discussed word of the market. Well also learn how they are different from Promises (havent heard about Promises? Not to worry! You will know more soon). Let’s s…

Spring Boot项目错误:Error parsing lifecycle processing instructions

pom.xml文件错误&#xff1a;Error parsing lifecycle processing instructions 解决方法&#xff1a;清空.m2/repository下的所有依赖文件&#xff0c;重新下载即可解决该问题。转载于:https://www.cnblogs.com/EasonJim/p/7724683.html

oracle执行计划连接方式

嵌套循环&#xff08;Nested Loops &#xff08;NL&#xff09;&#xff09;假如有A、B两张表进行嵌套循环连接&#xff0c;那么Oracle会首先从A表中提取一条记录&#xff0c;然后去B表中查找相应的匹配记录&#xff0c;如果有的话&#xff0c;就把该条记录的信息推到等待返回的…

大转盘完整源码附效果图,可以下载直接用

本转盘实现功能&#xff0c;可以动态配置奖品和转盘相关的任何图片&#xff0c;可以灵活配置使用。是基于 uni-app 实现的。可以在小程序或者H5&#xff0c;各端兼容使用。 效果图&#xff1a;因为GIF图的掉帧&#xff0c;所以显示抽奖的转动速度慢&#xff0c;实际上转动比较…