-
2020-03-24 16:45:15更多相关内容
-
网络游戏-一种游戏服务器热更新方法、装置与系统.zip
2021-09-20 06:24:43网络游戏-一种游戏服务器热更新方法、装置与系统.zip -
lua游戏服务器热更新
2016-10-07 19:00:17Lua热更新实现 用途 在生产环境上,总有可能出现不可预知的Bug,而通常修改好Bug仅仅又修改几句,停机维护的成本又太高,对于游戏来说,通常每个服就是单独的进程,也做不到像分布式环境下,关掉一部分机器,...Lua热更新实现
用途
在生产环境上,总有可能出现不可预知的Bug,而通常修改好Bug仅仅又修改几句,停机维护的成本又太高,对于游戏来说,通常每个服就是单独的进程,也做不到像分布式环境下,关掉一部分机器,先升级一部分,再升级另一部分的无缝升级。这时候如果有热更就可以迅速的把Bug修复方案通过热更新进行修复,不会对用户任何的影响。例如:
- 业务逻辑有Bug
- 配置的数据有误
- 需求发生变更
热更新的原则
1、热更新不破坏原有数据
热更新更新的基本内容就是更新服务的逻辑,通常只是逻辑发生变化,但原有的值并不能被改变,例如:
local a = 1 function get_a() return a end
此时,我们调用get_a()返回是的1,我们将热更成
local a = 2 function get_a() print("get_a function") return a end
此时我们改变了a的初始值,但我们并不知道之前服务a的值是不是被重新赋过值,假设热更前a的值仍然为1,那么我们热更后调用get_a()返回的应该是1,而不应受新的初始值影响,而且同能打印出了"get_a function",这时候则认为热更正常。
2、不为热更新写更多的代码
热更新可以通过很多种方法实现,比如说模块为了支持数据不变的特性,需要在模块里额外写一些代码来记录旧值,热更新之后再把旧值copy过来,或者用一些特殊的语法来支撑。这种方法将会对项目增加很多的负担,而且一旦发生意料之外的Bug,热更系统几乎处于半瘫痪状态。应该来说,代码原本该怎么实现就怎么实现,对于99%的lua代码都是支持的,不需要修改来迎合热更新。通常热更新不改变原有变量值的类型。
热更新的实现,代码适用于5.2以上
原理
利用_ENV环境,在加载的时候把数据加载到_ENV下,然后再通过对比的方式修改_G底下的值,从而实现热更新,函数
function hotfix(chunk, check_name)
定义env的table,并为env设置_G访问权限,然后调用load实现把数据重新加载进来
local env = {} setmetatable(env, { __index = _G }) local _ENV = env local f, err = load(chunk, check_name, 't', env) assert(f,err) local ok, err = pcall(f) assert(ok,err)
此时env我们可以得到新函数有变更的部分,我们替换的为可见变量,也就是可直接访问的变量
for name,value in pairs(env) do local g_value = _G[name] if type(g_value) ~= type(value) then _G[name] = value elseif type(value) == 'function' then update_func(value, g_value, name, 'G'..' ') _G[name] = value elseif type(value) == 'table' then update_table(value, g_value, name, 'G'..' ') end end
通过env当前的值和_G当前的值进行对比
- 如果类型不同我们直接覆盖原值,此时value不为nil,不会出现原则被覆盖成nil的情况
- 如果当前值为函数,我们进行函数的upvalue值比对
function update_func(env_f, g_f, name, deep) --取得原值所有的upvalue,保存起来 local old_upvalue_map = {} for i = 1, math.huge do local name, value = debug.getupvalue(g_f, i) if not name then break end old_upvalue_map[name] = value end --遍历所有新的upvalue,根据名字和原值对比,如果原值不存在则进行跳过,如果为其它值则进行遍历env类似的步骤 for i = 1, math.huge do local name, value = debug.getupvalue(env_f, i) if not name then break end local old_value = old_upvalue_map[name] if old_value then if type(old_value) ~= type(value) then debug.setupvalue(env_f, i, old_value) elseif type(old_value) == 'function' then update_func(value, old_value, name, deep..' '..name..' ') elseif type(old_value) == 'table' then update_table(value, old_value, name, deep..' '..name..' ') debug.setupvalue(env_f, i, old_value) else debug.setupvalue(env_f, i, old_value) end end end end
- 如果当前值为table,我们遍历table值进行对比
local protection = { setmetatable = true, pairs = true, ipairs = true, next = true, require = true, _ENV = true, } --防止重复的table替换,造成死循环 local visited_sig = {} function update_table(env_t, g_t, name, deep) --对某些关键函数不进行比对 if protection[env_t] or protection[g_t] then return end --如果原值与当前值内存一致,值一样不进行对比 if env_t == g_t then return end local signature = tostring(g_t)..tostring(env_t) if visited_sig[signature] then return end visited_sig[signature] = true --遍历对比值,如进行遍历env类似的步骤 for name, value in pairs(env_t) do local old_value = g_t[name] if type(value) == type(old_value) then if type(value) == 'function' then update_func(value, old_value, name, deep..' '..name..' ') g_t[name] = value elseif type(value) == 'table' then update_table(value, old_value, name, deep..' '..name..' ') end else g_t[name] = value end end --遍历table的元表,进行对比 local old_meta = debug.getmetatable(g_t) local new_meta = debug.getmetatable(env_t) if type(old_meta) == 'table' and type(new_meta) == 'table' then update_table(new_meta, old_meta, name..'s Meta', deep..' '..name..'s Meta'..' ' ) end end
更新
1、可以调用hotfix_file对整个文件进行热更
function hotfix_file(name) local file_str local fp = io.open(name) if fp then io.input(name) file_str = io.read('*all') io.close(fp) end if not file_str then return -1 end return hotfix(file_str, name) end
2、可以通过hotfix进行代码的更新
function hotfix(chunk, check_name)
关于坑
这里有一个注意事项,lua的module模块,如:
module("AA", package.seeall)
当我们加载lua模块的时候,这时候这个模块信息并不像初始化全局代码一样,就算提前设置了package.loaded["AA"] = nil, 也不会出现在env中同时也不会调用_G的__newindex函数,也就是说env["AA"]为空,故这种写法无法进行热更新,所以通常模块的写法改成如下
--定义模块AA AA = {} --相当于package.seeall setmetatable(AA, {__index = _G}) --环境隔离 local _ENV = AA
-
服务器热更新的讨论
2018-08-25 19:55:30之前对代码热更新预料不足,导致在线上出了一些bug时非常被动,往往需要重启服务器解决问题,影响前期的体验。我们的游戏类型是一个RPG卡牌游戏,操作偏向于单机向,大量依赖于广播的操作比较少。 这周的时间里,...我们之前的服务器是多进程纯C#架构的服务器。最近游戏上线,遇到有时候需要线上修bug的问题。之前对代码热更新预料不足,导致在线上出了一些bug时非常被动,往往需要重启服务器解决问题,影响前期的体验。我们的游戏类型是一个RPG卡牌游戏,操作偏向于单机向,大量依赖于广播的操作比较少。
这周的时间里,也考虑了几种方案,下面对比下思考的结果。
嵌入动态脚本
首先,C#+python或者lua的游戏服务器解决方案没有成功实例。现在最有名的ulua和xlua都是基于unity引擎的,在服务器的性能和承载上没有无法验证。没有成熟框架情况下,脚本和非脚本分层等如何来设定,还是需要比较多的设计和开发时间的。
其次,程序员使用脚本语言进行编程比用C#进行敏捷编程效率会差,vs等工具对于效率、正确性提升的红利会消失。此外,也是公司自己的原因,整体转变带来了不可预估的时间成本,以后的项目使用lua开发正确性能不能保障,会不会出现更多的bug?
其他的一些问题。比如一些自动化的代码(配置表,网络数据发送)往往需要在宿主语言和脚本语言上都实现一份等。这些工作会带来不少额外的工作量。
mono代码热更新
因为最终服务器是运行在linux环境下,用mono运行的,而mono是完全开源的。曾经有一位163的牛逼同事,实现了这么一套热更新的方案。方案原理是可以在运行时让mono把内存中的xxx.exe的某一些代码片段改掉,或是把入口重定向掉。
这种方法可以用来修一些bug,但很难去做一些小型新功能的支持。因为原型仅仅可以支持代码片段IL代码的改写,没法支持对新类型的操作等。
另一个缺点是,部分语法比较难以替换,比如泛型函数,闭包访问hold住的对象等,这些在虚拟机层面实现也是比较复杂的语法,在做mono热更新时就会是一些坑点的。如果我们可以完美支持mono热更新,需要了解很多底层语法的机制,那开发量可能与重写一个mono处于一个量级。
最后一个缺点是,热更新操作不如lua热更新直观。需要先编译出新的xxx.exe,然后通过工具生成出新老exe的il差,并导出成mono可以识别的文本。最后,线上触发mono去加载这个文本进行替换。而这里的步骤在lua热更新中,只需要简单的把错误的xxx.lua替换一次就可以了,我们的操作明显复杂。
实现无状态服务器
这一点主要是因为我们期望的游戏服务器类型是一个比较单机化的类卡牌游戏,才有可能这么去实现一个服务器架构。无状态服务器的最大优点是,逻辑和存储分离。也就是逻辑处理服务器只有处理器,没有状态,有点类似于actor模型;而存储服务器(可以是redis,也可以自己实现)则之提供存储和读取数据等简单稳定接口,保障存储服务器的稳定,就没有对存储服务器进行热更新的需求了。
这种框架之下,逻辑处理服务器就可以比较随意的重启了,以此实现了基于冷更新的服务器更新功能,但是玩家并不会感受到游戏更新或是断开。这种情况下,同时运行的几个服务器进程在某段时间内可能是不同版本的,可以实现一个版本逐步更替的过程。
这个方案会带来一些复杂性
- 需要一个调度服务器(CONTROLSV)调度新的LOGICSV替代旧的服务器的过程,所以这个服务器需要维护已有的服务器组。
- 需要拆分出一个能够配合存储流程的转有存储节点STORESv
- LOGICSv的逻辑代码,当需要访问和存储数据时,原本只需要访问内存对象,现在需要异步访问。增加了代码编写的复杂度。
- LOGICSv节点因为没有数据,如果要发起一些主动的update操作,也要异步去db取数据再改写。更严重的是,在操作大量数据时(比如对所有在线玩家update),会造成内部io和访问延迟比较大,并可能造成和玩家线程存取数据的冲突。
-
服务器热更新(当个文件更新)
2017-01-23 16:12:35上一篇文章我介绍了如果动态加载dll文件来更新程序 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文件。便利性不是很高。 那么有么有办法能做到动态实时更新呢???? ...上一篇文章我介绍了如果动态加载dll文件来更新程序
可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文件。便利性不是很高。
那么有么有办法能做到动态实时更新呢????
官方提供了这两个对象,动态编译源文件。
提供对 C# 代码生成器和代码编译器的实例的访问。 CSharpCodeProvider 提供一下方法加载源文件, // 基于包含在 System.CodeDom.CodeCompileUnit 对象的指定数组中的 System.CodeDom 树,使用指定的编译器设置编译程序集。 public virtual CompilerResults CompileAssemblyFromDom(CompilerParameters options, params CodeCompileUnit[] compilationUnits); // 从包含在指定文件中的源代码,使用指定的编译器设置编译程序集。 public virtual CompilerResults CompileAssemblyFromFile(CompilerParameters options, params string[] fileNames); // 从包含源代码的字符串的指定数组,使用指定的编译器设置编译程序集。 public virtual CompilerResults CompileAssemblyFromSource(CompilerParameters options, params string[] sources);
上面的方法我测试了CompileAssemblyFromFile CompileAssemblyFromSource 两个方法,
CompileAssemblyFromFile 的意思给定文件路径去编译源文件,可以直接加入调试信息,调试,
CompileAssemblyFromSource 的意思给定源码类容去编译源文件,无法直接加入调试信息,需要加入 System.Diagnostics.Debugger.Break(); 在源文件插入断点调试。但是在除非断点的时候会弹出对话框,跳转指定源文件附近才能调试。略微麻烦。
以上两种方法需要调试都需要下面的调试参数配合 IncludeDebugInformation = true; 才能有用
表示用于调用编译器的参数。 CompilerParameters 提供一下参数 //不输出编译文件 parameter.GenerateExecutable = false; //生成调试信息 parameter.IncludeDebugInformation = true; //不输出到内存 parameter.GenerateInMemory = false; //添加需要的程序集 parameter.ReferencedAssemblies.AddRange(tempDllNames);
废话不多说,我们来测试一下代码
首先创建一个 LoadManager.cs
public class LoadManager { private static LoadManager instance = new LoadManager(); public static LoadManager GetInstance { get { return instance; } } public void LoadFile(string path) { CSharpCodeProvider provider = new CSharpCodeProvider(); CompilerParameters parameter = new CompilerParameters(); //不输出编译文件 parameter.GenerateExecutable = false; //生成调试信息 parameter.IncludeDebugInformation = true; //不输出到内存 parameter.GenerateInMemory = false; //添加需要的程序集 parameter.ReferencedAssemblies.Add("System.dll"); //编译文件 Console.WriteLine("动态加载文件:" + path); CompilerResults result = provider.CompileAssemblyFromFile(parameter, path);//根据制定的文件加载脚本 //判断是否有错误 if (!result.Errors.HasErrors) { //获取加载的所有对象模型 Type[] instances = result.CompiledAssembly.GetExportedTypes(); foreach (var itemType in instances) { Console.WriteLine("生成实例:" + itemType.Name); //生成实例 object obj = Activator.CreateInstance(itemType); } } else { var item = result.Errors.GetEnumerator(); while (item.MoveNext()) { Console.WriteLine("动态加载文件出错了!" + item.Current.ToString()); } } } }
创建测试源文件 TestCode.cs
public class TestCode { public TestCode() { Console.WriteLine("我是TestCode"); } }
调用测试
string cspath = @"F:\javatest\ConsoleApplication6\CodeDomeCode\TestCode.cs"; LoadManager.GetInstance.LoadFile(cspath);
输出结果 表面我们加载成功了,
动态加载文件:F:\javatest\ConsoleApplication6\CodeDomeCode\TestCode.cs 生成实例:TestCode 我是TestCode
接下来我们
修改一下 TestCode.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CodeDomeCode { public class TestCode { public TestCode() { Console.WriteLine("我是TestCode"); } } }
结果程序输出错误
动态加载文件:F:\javatest\ConsoleApplication6\CodeDomeCode\TestCode.cs 动态加载文件出错了!f:\javatest\ConsoleApplication6\CodeDomeCode\TestCode.cs(3,14) : error CS0234: 命名空间“System”中不存在类型或命名空间名称“Linq”(是否缺少程序集引用?)
这就出现了一个问题,
//添加需要的程序集 parameter.ReferencedAssemblies.Add("System.dll");
我们的编译参数。附件编译依赖程序集的只添加了 System.dll 文件,所有导致编译出错。
那么我们知道思考一个问题,这个依赖程序集,必须要手动添加嘛?是不是太费事 ?
如果是做公共模块的话。我这么知道需要哪些依赖程序集呢?
系统提供了AppDomain.CurrentDomain.GetAssemblies();获取当前程序集所有程序集
Assembly.GetModules();程序集依赖项;
既然这样,我们是不是可以依赖当前应用程序域加载呢?
修改一下依赖程序集添加方式
HashSet<String> ddlNames = new HashSet<string>(); var asss = AppDomain.CurrentDomain.GetAssemblies(); foreach (var item in asss) { foreach (var item222 in item.GetModules(false)) { ddlNames.Add(item222.FullyQualifiedName); } } //添加需要的程序集 parameter.ReferencedAssemblies.AddRange(ddlNames.ToArray());
编译完成,依赖于依赖当前应用程序域加载依赖程序集;(需要注意的时候你的代码里面依赖的程序集,当前应用程序域也需要加载)
动态加载文件:F:\javatest\ConsoleApplication6\CodeDomeCode\TestCode.cs 生成实例:TestCode 我是TestCode
接下来我们看看如何才能加入调试情况呢?
有两个问题,如果要加入调试,需要修改两个参数才能加入断点调试
//生成调试信息 parameter.IncludeDebugInformation = true; //输出编译对象到内存 parameter.GenerateInMemory = true;
在代码中直接加入断点测试
运行起来
进入断点调试了。
如果是源文件是文本文件但是需要加入调试的话;
System.Diagnostics.Debugger.Break();
我们看到加入了调试了,两种方式都能加入调试信息;
问题继续出现,我们在加载源文件的时候,需求里面肯定存在更新所加载的源文件吧。
而且加载的文件对象肯定需要保存提供调用;
修改程序。
使用线程安全的集合保存所加载的实例对象
ConcurrentDictionary<string, ConcurrentDictionary<string, object>> Instances = new ConcurrentDictionary<string, ConcurrentDictionary<string, object>>();
//获取加载的所有对象模型 Type[] instances = assembly.GetExportedTypes(); foreach (var itemType in instances) { //获取单个模型的所有继承关系和接口关系 Type[] interfaces = itemType.GetInterfaces(); //生成实例 object obj = Activator.CreateInstance(itemType); foreach (var iteminterface in interfaces) { //判断是否存在键 if (!Instances.ContainsKey(iteminterface.Name)) { Instances[iteminterface.Name] = new ConcurrentDictionary<string, object>(); } //无加入对象,有更新对象 Instances[iteminterface.Name][itemType.Name] = obj; } }
把对象加入到集合中
/// <summary> /// 返回查找的脚本实例 /// </summary> /// <typeparam name="T">类型</typeparam> /// <returns></returns> public IEnumerable<T> GetInstances<T>() { //使用枚举迭代器,避免了再一次创建对象 string typeName = typeof(T).Name; if (Instances.ContainsKey(typeName)) { foreach (var item in Instances[typeName]) { if (item.Value is T) { yield return (T)item.Value; } } } }
最后附加全套源码
提供 源文件 .cs 和程序集加载 .dll
提供支持路径递归加载和指定文件加载方式,并且提供了后缀筛选和附加dll加载。
View Code
/** * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 * */ 跪求保留标示符 本程序猿所有博客园相关全套源码奉献 淘宝SVN。特别鸣谢淘宝SVN提供免费仓储。 http://code.taobao.org/svn/flynetwork_csharp/trunk/Flynetwork/BlogTest
-
详解如何热更新线上的Java服务器代码
2020-08-19 06:26:49主要介绍了详解如何热更新线上的Java服务器代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
从nginx热更新聊一聊Golang中的服务器热更新(上)
2019-03-14 00:10:01最近花了点时间看了下nginx热更新代码流程,想了下结合之前的经验一并总结下热更新 1. 热更新是什么? 简单翻译成人类可读的实例是如下这个样子: 举个例子,你现在在坐卡车,卡车开到了150KM/H 然后,有个轮胎,... -
Unity Addressable学习笔记三(远程服务器热更新)
2021-01-22 10:45:08上篇讲解了使用Unity内置的HostingService来热更资源,但是在自己的正式项目还是需要自己去布置资源服务器。上篇步骤全部实现本篇就非常简单了,仅仅只是更改远程Load路径,然后将Build的包上传到服务器就好。 点击... -
服务器热更新(动态加载DLL)
2017-01-23 16:10:38大家可能对游戏服务器的运行不太理解或者说不太清楚一些机制。 但是大家一定会明白一点,当程序在运行的时候出现一些bug,必须及时更新,...那么就牵涉到程序热更新修复bug功能。 今天就来扒一扒热更新的事情。 -
IDEA SpringBoot项目配置热更新的步骤详解(无需每次手动重启服务器)
2020-08-19 07:19:13主要介绍了IDEA SpringBoot项目配置热更新的步骤,无需每次手动重启服务器,本文通过图文实例代码相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 -
搭建服务器进行热更新 Addressable server and hot update
2021-02-19 10:34:25搭建服务器 买一台阿里云服务器,不需要域名,记下外网IP 安装JDK:https://www.oracle.com/java/technologies/javase-downloads.html,安装版(非zip)会自动设置环境变量 安装apache Tomcat:... -
服务器配置热更新
2018-03-22 15:58:00服务器配置热更新 中文(中国)Toggle Dropdown Keywords: 配置,热更新 此功能能够允许你在不重启服务器的前提下更新服务器实例的配置。(仅限1.6.5及其以上版本) 支持热更新的服务器实例配置选项 Super... -
Unity 热更新资源本地IIS服务器配置
2018-08-14 17:12:50接下来配置本地IIS服务器: 下图根据自己喜好随意填: 然后选择应用程序池,找到刚才写的网站名称,右键选择基本设置,.Net V4版本,集成,确定。 选择自己网站的名称... -
用nodejs+express搭建一个热更新服务器
2020-05-02 03:20:18最近在看cocos creator的热更新部分,官网上给出了简单案例,但是没有给出热更新服务器的搭建方法。之前完全没搞过服务器,这次尝试搭建了一个。 环境 1、vscode版本 vscode 1.44.2 2、node.js版本 nodejs4.6.2 3、... -
创建一个本地的资源更新服务器(unity热更新篇)
2020-06-05 16:22:54最近为了测试热更新,所以需要本地建立一个资源服务器。 使用WWW www = new WWW(url)来请求服务器assetsbundle资源. 使用C#建立一个http服务 using (var httpListener = new HttpListener()) { httpListener... -
热更新部署工具
2018-12-26 15:09:00本工具能实现本地资源和热更服务器资源对比差异上传,window form 设计更简单操作,为了商业保密本工具的oss地址及账号密码均已隐藏,喜欢的可以下载参考 -
JAVA服务器热更新
2018-01-05 11:19:21看下来instrumentation是最好用的,除了不能增加或者删除方法外。 直接上代码: public class Agent{ public static Instrumentation INST = null; ...public static void premain(String agentArgs, ... -
Autojs-hot-update:Auto.js的脚本热更新demo
2021-05-28 17:44:18热更新服务器已关闭,但代码还可以看看 使用说明请查看:使用说明.txt 备注:这个demo只是解决测试时反复打包的困扰, 不建议最终打包给用户时使用。 当然,如果你的用户不会抓包等操作, 那就可以继续使用。否则,... -
Unity3d 基于xlua热更新实现系列四(终章):构建资源服务器实现真正热更新的压缩包下载、解压和更新功能...
2022-03-30 17:37:49建议先看说明:https://blog.csdn.net/qq_33789001/article/details/123852424 包含更新检测、资源下载、解压更新等热更新的完整功能。 -
热更新部署代码jar包
2018-11-03 12:23:04热更新示例可以便于服务器端进行热部署 !图表设计实际上就是数据可视化设计,美观的图表设计可以让数据分析变得轻松、流畅、并且易读,将更有助于提高用户的工作效率,降低用户的工作负担。RDP报表工具不仅具有经典... -
在window上安装supervisor(nodejs服务器热更新)
2018-02-08 17:55:20npm i -g supervisor找到app.js所在目录,输入命令:supervisor app.js如果端口冲突,则需将原来启动的服务关闭即可。参考链接:点击打开链接 -
Vue 热更新配置
2020-04-30 14:53:01在vue项目中新建 vue.config.js 配置 module.exports = { devServer : { hot:true, open : true, port : 8080, host : "127.0.0.1" } } -
热更新 本地资源和服务器资源目录
2019-05-20 17:51:22服务器资源: 最外层三层文件夹目录 Pro Pre qa 每个文件夹分别包括至少两个文件(版本号+MD5File.json和Version.json)和一个文件夹assets 1、版本号+MD5File.json:(1)版本号用来确定当前版本读取当前版本的... -
express 热更新方法
2019-09-29 06:33:53npm install -g node-dev或npm install node-dev -D 然后在package.json里加上"dev": "node-dev ./bin/www" 转载于:https://www.cnblogs.com/ft039x/p/11281932.html -
WebpackHotServerMiddleware实现在服务器上热更新Webpackbundles
2019-08-10 03:52:28Webpack Hot Server Middleware:实现在服务器上热更新Webpack bundles -
spring boot 热更新,热部署
2019-04-03 16:09:00近来在使用idea做springboot的项目,但是发现每次修改之后我都需要重新将项目关闭再开启,这样比较繁琐,发现通过热部署的方式让我们可以一边修改我们的项目,然后在页面中直接通过刷新展示出来 spring为开发者提供... -
Webpack配置热更新web服务
2018-12-09 08:55:171、安装插件 npm install webpack-dev-server --save-dev ...2、package.json中配置script启动脚本 ...--host:可以指定服务器的 ip,不指定则为127.0.0.1 3、运行脚本 npm run dev 4、测试 -
game-hot-update:Java游戏服务器热更例子。此热更新方法采用启用后更新。即游戏服务器在运行中如果出现bug,...
2021-05-15 17:48:04Java游戏服务器热更例子。此热更新方法采用启用后更新。即游戏服务器在运行中如果出现bug,采用pid绑定的方式更新。此更新方法只允许更新方法体内的代码。比如一个类某个方法有bug,在方法体内修改完之后可以热更,...