1.《开端》和《源代码》的辅助辅助剧情是否有雷同之处?
2.如何解读 tn6 文件源码?
3.开端是模仿什么**
4.网剧《开端》是否借鉴了《源代码》里的创意?
5.umi3源码解析之核心Service类初始化
《开端》和《源代码》的剧情是否有雷同之处?
《开端》这部剧在播出之后,就受到了许多人的开端开端关注,无限流的源码源码设定,也让人们感觉到新鲜。辅助辅助不过像这些设定也让人们想起了一部非常有名的开端开端影片《源代码》,所以有人会觉得《开端》对《源代码》有所抄袭,源码源码快播开源码但实际上除了剧情的辅助辅助梗概比较相似以外,剧情的开端开端细节上并没有什么相同的。所以说《开端》并没有抄袭**《源代码》,源码源码两个作品都是辅助辅助很优秀的,而且各有千秋。开端开端《开端》和《源代码》之所以会有人觉得《开端》抄袭的源码源码《源代码》 ,就是辅助辅助由于这两个故事发生的主体比较相似。《开端》是开端开端发生在公交车上的循环,而《源代码》则是源码源码发生在火车上的循环。另外都是由男女两个主角进入到循环并且不断的拯救车上人的故事,虽然说梗概有一些相似。但是要知道无限流的设定在很多的影视剧中都有出现,而且这种为了突出男女主的特色,所以说不断的去进行拯救他人的剧情设定也是比较常规的,所以说并没有什么抄袭的。再加上《开端》从刚开始播出到之后都没有任何剧情上的重复点,而且也非常能够吸引观众的注意力,所以说编剧在设计剧情的过程中是非常细心的,所以说两者并没有任何的抄袭情况,也能够体现网友们对于《开端》剧情的关注,所以好剧只要欣赏就够了,没有必要过分的担心。
《开端》的播出从刚开始播出的社会讨论度很高,很多人也被这些年轻。演员的演技提升和突破感到十分的吃惊。当然在这部剧中更多的人是能够看到编剧的细心,所以好剧就要体现在各个细节上以及制作特色上,这样的话才能够让更多的人可以给予好评。
总结一部好剧有相似点是很正常的,但是只要能够体现自身的特色就可以了。并且《开端》这部剧在海内外都取得了不错的播出效果,也希望有更多的坏坏猫app源码人能够通过这部剧来获得观看的喜悦。
如何解读 tn6 文件源码?
深入解析腾讯网游资源基石:tn6文件源码解读
在探索腾讯网游的幕后世界中,tn6文件扮演着至关重要的角色,它是游戏角色、地图和界面等资源的神秘载体。要揭开tn6文件的神秘面纱,我们需要理解其独特的结构和工作原理。接下来,我们将一起探索这个二进制宝藏的内部构造,揭示其解读的关键步骤。
首先,tn6文件以"TN6"这一标志性的魔数为开端,宣告了其二进制身份。文件由一系列的"Chunk"组成,这些Chunk就像是资源的模块,每个都有自己固定的格式。每个Chunk由三个基本元素构成:Chunk ID、大小和数据。Chunk ID如同资源的身份证,不同的ID代表着地图、模型、纹理等不同类型的资源,通过它,我们能定位到相应的数据。
Chunk数据部分则是压缩后的,常见压缩算法如LZMA和zlib使得数据更为紧凑。为了访问这些资源,tn6文件还有一个目录表,它就像是一个索引,记录了每个Chunk的精确位置,使得快速查找变得轻而易举。
要解析tn6文件,犹如解码一部精密的蓝图,我们需要遵循以下步骤:
1. 验证身份:以二进制方式打开文件,检查头4个字节是否为"TN6",确保我们正在处理的是tn6文件。
2. 解锁目录:读取目录表,获取每个Chunk的php在线翻墙源码存储位置,这是解析的钥匙。
3. 逐个解锁:遍历每个Chunk,解读Chunk ID,识别其包含的资源类型,如地图、模型或纹理。
4. 解压缩数据:针对特定类型的资源,从文件中读取并解压数据,还原出原始信息。
5. 重构结构:将解压后的数据转换为游戏理解的格式,比如地图的网格,模型的坐标等。
6. 激活资源:将解析出的资源加载到游戏中,为玩家呈现丰富的内容。
举个例子,一个简单的tn6文件解析器可能会这样实现(以Python为例):
```python
with open('test.tn6', 'rb') as f:
# 验证文件类型
magic = f.read(4)
# 读取目录表
chunk_offsets = read_chunk_offset_table(f)
for offset in chunk_offsets:
# 跳转到Chunk位置
f.seek(offset)
# 识别资源类型
chunk_id = f.read(4)
if chunk_id == b'MAP ':
# 解压并解析地图数据
map_data = decompress_chunk(f)
parse_map(map_data)
elif chunk_id == b'MODL':
# 解压并解析模型数据
model_data = decompress_chunk(f)
parse_model(model_data)
# ...继续处理其他资源类型
这个基础的解析器框架为你解读tn6源码提供了一个起点。深入理解tn6文件源码,将为你打开通往游戏世界背后技术的门。如果你在解析过程中遇到任何疑惑,欢迎在讨论区分享,让我们一起深入探索这个数据的海洋。
开端是模仿什么
**《开端》模仿的是《源代码》**。两个影视作品,在剧情的艺术表现手法上,一模一样,全是讲时间循环。《源代码》是由邓肯·琼斯执导,杰克·吉伦哈尔、维拉·法米加、米歇尔·莫娜汉等人联袂出演。影片于年4月1日在美国上映。影片讲述了一位在阿富汗执行任务的美国空军飞行员柯尔特·史蒂文斯,醒来时发现自己正处在一辆前往芝加哥的火车上,并就此经历的一系列惊心动魄的事件。
《源代码》剧情简介,咚,咚、lib如何连接源码呼,呼,急促的心跳声和喘息声震耳欲聋。一切都开始模糊,继而扭曲变形。然后,一阵尖锐的火车汽笛声,将柯尔特·斯蒂文斯上尉(杰克·吉伦哈尔 饰演)拉回了现实。窗外,是疾驰倒退的绿地;坐在他对面的女子(米歇尔·莫娜汉 饰演)疑惑地看着走神的他,又继续着话题,柯尔特突然觉得头皮发麻;他不是这个女子口中的肖恩,也压根儿就不认识眼前这个叫做克里斯蒂娜的女子,他所记得的最后一件事情,是自己正在阿富汗执行飞行任务。
《源代码》导演邓肯·琼斯凭借科幻首作《月球》声名鹊起后,被制片商选中成为《源代码》的导演,得到的不仅仅是几倍的预算和设备,更获得强大幕后班底的加盟支持:《》、《后天》的制片人马克·戈登,《异种3》编剧本·雷普利,《阿甘正传》摄影师唐·博格斯及《谍中谍》剪辑保罗·赫希。演员方面更是邀请来好莱坞小生杰克·吉伦哈尔。
《源代码》影片于年4月1日在美国本土上映,共在家戏院放映,首映当天收入票房万美元。影片于年8月日在中国上映,上映6天,共放映次数场,观众人次为人,累计票房收入万币,荣登年第周中国票房榜榜首。
《源代码》这个影片讲述一个死人试图从核灾难中拯救芝加哥的故事,充满悬念,制作,一部经典的恐怖作品。
《开端》是企业建站商用源码由东阳正午阳光影视有限公司出品,孙墨龙、刘洪源、算共同执导,由白敬亭、赵今麦领衔主演,刘奕君特别出演,刘涛友情出演,黄觉、刘丹等主演的时间循环短剧。于年1月日在腾讯视频独播。该剧改编自祈祷君的同名小说,讲述了游戏架构师“肖鹤云”和在校大学生“李诗情”遭遇公交车爆炸后死而复生,在时间循环中并肩作战,努力阻止爆炸、寻找真相的故事。
剧情简介:李诗情(赵今麦饰)梦见她乘坐的路公交车,在走向跨江大桥时爆炸了,她也因为爆炸被吓醒。醒来后她发现公交车上的经历居然和梦境一模一样,在多次努力尝试阻止爆炸未果后,确信自己进入了时间循环。与此同时,第六次时间循环时被强行拽下车的肖鹤云(白敬亭饰)也和李诗情一起进入了循环。两个普通的年轻人在一次又一次的循环中,经历了生死挑战,实现了自我成长,也了解到了路公交车上身份各异的乘客们背后的故事。最终在二人和警方的共同努力下,终于寻找到了爆炸的真相。正义终会来临,正如俩人名字所预示的那般,迎来“晴空一鹤排云上,便引诗情到碧霄”的清朗开阔。
网剧《开端》是否借鉴了《源代码》里的创意?
网剧《开端》确实借鉴了《源代码》里的创意,两个的区别:《开端》应该是借鉴了《源代码》形式,但细节处却显示出不同文化背景下的世界观,《源代码》交代了意识濒死状态下,科技可以开启短暂的(8分钟)的“薛定谔的猫”,源代码可以延展出无限可能,而源代码永生,《开端》则避开了技术推动,貌似是世界出现了bug,不阐述触发缘由及过程,而强调结果。《源代码》触发平行空间,并联;《开端》则幸运轮回,讲求最后的因果,串联。补充下,导演抠细节实在疯狂,画面,服饰颜色都在努力表达隐喻,有“正午阳光宇宙”的味道。
故事框架有相似之处:都是在车上遭遇了炸弹,主角一次次“穿越”回去,排除了几个嫌疑对象后,最终都找出了凶手,解决炸弹危机。都是男女主合作的模式,最终都爱上了。差别其实很大:两部题材和篇幅完全不同,一部是**,一部是短剧,改编自同名小说。《源代码》是科幻题材,“穿越”有科学的设定和解释,戏里男主其实已经死了,被他附体的人也死了,他并不能改变过去,他只是潜入别人的记忆里,找出凶手和炸弹,阻止凶手继续作恶,找出凶手其实就算完成任务了,歹徒会由空军去抓。
《源代码》只有男主能“穿越”,女主并不能“穿越”。男主跟空军技术团队有不少戏份。男主遭遇的困难少一些,没《开端》那么曲折。《开端》虽然设定很荒诞,但属于现实题材,有认真探讨和呈现很多现实问题。
综上所述,如果只是看故事梗概的话,确实会觉得《开端》抄了《源代码》,但其实两者是截然不同的,《开端》的创作最多只是从《源代码》受到了启发。
umi3源码解析之核心Service类初始化
前言
umi是一个插件化的企业级前端应用框架,在开发中后台项目中应用颇广,确实带来了许多便利。借着这个契机,便有了我们接下来的“umi3源码解析”系列的分享,初衷很简单就是从源码层面上帮助大家深入认知umi这个框架,能够更得心应手的使用它,学习源码中的设计思想提升自身。该系列的大纲如下:
开辟鸿蒙,今天要解析的就是第一part,内容包括以下两个部分:
邂逅umi命令,看看umidev时都做了什么?
初遇插件化,了解源码中核心的Service类初始化的过程。
本次使用源码版本为?3.5.,地址放在这里了,接下来的每一块代码笔者都贴心的为大家注释了在源码中的位置,先clone再食用更香哟!
邂逅umi命令该部分在源码中的路径为:packages/umi
首先是第一部分umi命令,umi脚手架为我们提供了umi这个命令,当我们创建完一个umi项目并安装完相关依赖之后,通过yarnstart启动该项目时,执行的命令就是umidev
那么在umi命令运行期间都发生了什么呢,先让我们来看一下完整的流程,如下图:
接下来我们对其几个重点的步骤进行解析,首先就是对于我们在命令行输入的umi命令进行处理。
处理命令行参数//packages/umi/src/cli.tsconstargs=yParser(process.argv.slice(2),{ alias:{ version:['v'],help:['h'],},boolean:['version'],});if(args.version&&!args._[0]){ args._[0]='version';constlocal=existsSync(join(__dirname,'../.local'))?chalk.cyan('@local'):'';console.log(`umi@${ require('../package.json').version}${ local}`);}elseif(!args._[0]){ args._[0]='help';}解析命令行参数所使用的yParser方法是基于yargs-parser封装,该方法的两个入参分别是进程的可执行文件的绝对路径和正在执行的JS文件的路径。解析结果如下:
//输入umidev经yargs-parser解析后为://args={ //_:["dev"],//}在解析命令行参数后,对version和help参数进行了特殊处理:
如果args中有version字段,并且args._中没有值,将执行version命令,并从package.json中获得version的值并打印
如果没有version字段,args._中也没有值,将执行help命令
总的来说就是,如果只输入umi实际会执行umihelp展示umi命令的使用指南,如果输入umi--version会输出依赖的版本,如果执行umidev那就是接下来的步骤了。
提问:您知道输入umi--versiondev会发什么吗?
运行umidev
//packages/umi/src/cli.tsconstchild=fork({ scriptPath:require.resolve('./forkedDev'),});process.on('SIGINT',()=>{ child.kill('SIGINT');process.exit(0);});//packages/umi/src/utils/fork.tsif(CURRENT_PORT){ process.env.PORT=CURRENT_PORT;}constchild=fork(scriptPath,process.argv.slice(2),{ execArgv});child.on('message',(data:any)=>{ consttype=(data&&data.type)||null;if(type==='RESTART'){ child.kill();start({ scriptPath});}elseif(type==='UPDATE_PORT'){ //setcurrentusedportCURRENT_PORT=data.portasnumber;}process.send?.(data);});本地开发时,大部分脚手架都会采用开启一个新的线程来启动项目,umi脚手架也是如此。这里的fork方法是基于node中child_process.fork()方法的封装,主要做了以下三件事:
确定端口号,使用命令行指定的端口号或默认的,如果该端口号已被占用则prot+=1
开启子进程,该子进程独立于父进程,两者之间建立IPC通信通道进行消息传递
处理通信,主要监听了RESTART重启和UPDATE_PORT更新端口号事件
接下来看一下在子进程中运行的forkedDev.ts都做了什么。
//packages/umi/src/forkedDev.ts(async()=>{ try{ //1、设置NODE_ENV为developmentprocess.env.NODE_ENV='development';//2、InitwebpackversiondeterminationandrequirehookinitWebpack();//3、实例化Service类,执行run方法constservice=newService({ cwd:getCwd(),//umi项目的根路径pkg:getPkg(process.cwd()),//项目的package.json文件的路径});awaitservice.run({ name:'dev',args,});//4、父子进程通信letclosed=false;process.once('SIGINT',()=>onSignal('SIGINT'));process.once('SIGQUIT',()=>onSignal('SIGQUIT'));process.once('SIGTERM',()=>onSignal('SIGTERM'));functiononSignal(signal:string){ if(closed)return;closed=true;//退出时触发插件中的onExit事件service.applyPlugins({ key:'onExit',type:service.ApplyPluginsType.event,args:{ signal,},});process.exit(0);}}catch(e:any){ process.exit(1);}})();设置process.env.NODE_ENV的值
initWebpack(接下来解析)
实例化Service并run(第二part的内容)
处理父子进程通信,当父进程监听到SIGINT、SIGTERM等终止进程的信号,也通知到子进程进行终止;子进程退出时触发插件中的onExit事件
initWebpack
//packages/umi/src/initWebpack.tsconsthaveWebpack5=(configContent.includes('webpack5:')&&!configContent.includes('//webpack5:')&&!configContent.includes('//webpack5:'))||(configContent.includes('mfsu:')&&!configContent.includes('//mfsu:')&&!configContent.includes('//mfsu:'));if(haveWebpack5||process.env.USE_WEBPACK_5){ process.env.USE_WEBPACK_5='1';init(true);}else{ init();}initRequreHook();这一步功能是检查用户配置确定初始化webpack的版本。读取默认配置文件.umirc和config/config中的配置,如果其中有webpack5或?mfsu等相关配置,umi就会使用webpack5进行初始化,否则就使用webpack4进行初始化。这里的mfsu是webpack5的模块联邦相关配置,umi在3.5版本时已经进行了支持。
初遇插件化该部分在源码中的路径为:packages/core/src/Service
说起umi框架,最先让人想到的就是插件化,这也是框架的核心,该部分实现的核心源码就是Service类,接下来我们就来看看Service类的实例化和init()的过程中发生了什么,可以称之为插件化实现的开端,该部分的大致流程如下
该流程图中前四步,都是在Service类实例化的过程中完成的,接下来让我们走进Service类。
Service类的实例化//packages/core/src/Service/Service.tsexportdefaultclassServiceextendsEventEmitter{ constructor(opts:IServiceOpts){ super();this.cwd=opts.cwd||process.cwd();//当前工作目录//repoDirshouldbetherootdirofrepothis.pkg=opts.pkg||this.resolvePackage();//package.jsonthis.env=opts.env||process.env.NODE_ENV;//环境变量//在解析config之前注册babelthis.babelRegister=newBabelRegister();//通过dotenv将环境变量中的变量从.env或.env.local文件加载到process.env中this.loadEnv();//1、getuserconfigconstconfigFiles=opts.configFiles;this.configInstance=newConfig({ cwd:this.cwd,service:this,localConfig:this.env==='development',configFiles});this.userConfig=this.configInstance.getUserConfig();//2、getpathsthis.paths=getPaths({ cwd:this.cwd,config:this.userConfig!,env:this.env,});//3、getpresetsandpluginsthis.initialPresets=resolvePresets({ ...baseOpts,presets:opts.presets||[],userConfigPresets:this.userConfig.presets||[],});this.initialPlugins=resolvePlugins({ ...baseOpts,plugins:opts.plugins||[],userConfigPlugins:this.userConfig.plugins||[],});}}Service类继承自EventEmitter用于实现自定义事件。在Service类实例化的过程中除了初始化成员变量外主要做了以下三件事:
1、解析配置文件
//packages/core/src/Config/Config.tsconstDEFAULT_CONFIG_FILES=[//默认配置文件'.umirc.ts','.umirc.js','config/config.ts','config/config.js',];//...if(Array.isArray(opts.configFiles)){ //配置的优先读取this.configFiles=lodash.uniq(opts.configFiles.concat(this.configFiles));}//...getUserConfig(){ //1、找到configFiles中的第一个文件constconfigFile=this.getConfigFile();this.configFile=configFile;//潜在问题:.local和.env的配置必须有configFile才有效if(configFile){ letenvConfigFile;if(process.env.UMI_ENV){ //1.根据UMI_ENV添加后缀eg:.umirc.ts-->.umirc.cloud.tsconstenvConfigFileName=this.addAffix(configFile,process.env.UMI_ENV,);//2.去掉后缀eg:.umirc.cloud.ts-->.umirc.cloudconstfileNameWithoutExt=envConfigFileName.replace(extname(envConfigFileName),'',);//3.找到该环境下对应的配置文件eg:.umirc.cloud.[ts|tsx|js|jsx]envConfigFile=getFile({ base:this.cwd,fileNameWithoutExt,type:'javascript',})?.filename;}constfiles=[configFile,//eg:.umirc.tsenvConfigFile,//eg:.umirc.cloud.tsthis.localConfig&&this.addAffix(configFile,'local'),//eg:.umirc.local.ts].filter((f):fisstring=>!!f).map((f)=>join(this.cwd,f))//转为绝对路径.filter((f)=>existsSync(f));//clearrequirecacheandsetbabelregisterconstrequireDeps=files.reduce((memo:string[],file)=>{ memo=memo.concat(parseRequireDeps(file));//递归解析依赖returnmemo;},[]);//删除对象中的键值require.cache[cachePath],下一次require将重新加载模块requireDeps.forEach(cleanRequireCache);this.service.babelRegister.setOnlyMap({ key:'config',value:requireDeps,});//requireconfigandmergereturnthis.mergeConfig(...this.requireConfigs(files));}else{ return{ };}}细品源码,可以看出umi读取配置文件的优先级:自定义配置文件?>.umirc>config/config,后续根据UMI_ENV尝试获取对应的配置文件,development模式下还会使用local配置,不同环境下的配置文件也是有优先级的
例如:.umirc.local.ts>.umirc.cloud.ts>.umirc.ts
由于配置文件中可能require其他配置,这里通过parseRequireDeps方法进行递归处理。在解析出所有的配置文件后,会通过cleanRequireCache方法清除requeire缓存,这样可以保证在接下来合并配置时的引入是实时的。
2、获取相关绝对路径
//packages/core/src/Service/getPaths.tsexportdefaultfunctiongetServicePaths({ cwd,config,env,}:{ cwd:string;config:any;env?:string;}):IServicePaths{ letabsSrcPath=cwd;if(isDirectoryAndExist(join(cwd,'src'))){ absSrcPath=join(cwd,'src');}constabsPagesPath=config.singular?join(absSrcPath,'page'):join(absSrcPath,'pages');consttmpDir=['.umi',env!=='development'&&env].filter(Boolean).join('-');returnnormalizeWithWinPath({ cwd,absNodeModulesPath:join(cwd,'node_modules'),absOutputPath:join(cwd,config.outputPath||'./dist'),absSrcPath,//srcabsPagesPath,//pagesabsTmpPath:join(absSrcPath,tmpDir),});}这一步主要获取项目目录结构中node_modules、dist、src、pages等文件夹的绝对路径。如果用户在配置文件中配置了singular为true,那么页面文件夹路径就是src/page,默认是src/pages
3、收集preset和plugin以对象形式描述
在umi中“万物皆插件”,preset是对于插件的描述,可以理解为“插件集”,是为了方便对插件的管理。例如:@umijs/preset-react就是一个针对react应用的插件集,其中包括了plugin-access权限管理、plugin-antdantdUI组件等。
//packages/core/src/Service/Service.tsthis.initialPresets=resolvePresets({ ...baseOpts,presets:opts.presets||[],userConfigPresets:this.userConfig.presets||[],});this.initialPlugins=resolvePlugins({ ...baseOpts,plugins:opts.plugins||[],userConfigPlugins:this.userConfig.plugins||[],});在收集preset和plugin时,首先调用了resolvePresets方法,其中做了以下处理:
3.1、调用getPluginsOrPresets方法,进一步收集preset和plugin并合并
//packages/core/src/Service/utils/pluginUtils.tsgetPluginsOrPresets(type:PluginType,opts:IOpts):string[]{ constupperCaseType=type.toUpperCase();return[//opts...((opts[type===PluginType.preset?'presets':'plugins']asany)||[]),//env...(process.env[`UMI_${ upperCaseType}S`]||'').split(',').filter(Boolean),//dependencies...Object.keys(opts.pkg.devDependencies||{ }).concat(Object.keys(opts.pkg.dependencies||{ })).filter(isPluginOrPreset.bind(null,type)),//userconfig...((opts[type===PluginType.preset?'userConfigPresets':'userConfigPlugins']asany)||[]),].map((path)=>{ returnresolve.sync(path,{ basedir:opts.cwd,extensions:['.js','.ts'],});});}这里可以看出收集preset和plugin的来源主要有四个:
实例化Service时的入参
process.env中指定的UMI_PRESETS或UMI_PLUGINS
package.json中dependencies和devDependencies配置的,需要命名规则符合?/^(@umijs\/|umi-)preset-/这个正则
解析配置文件中的,即入参中的userConfigPresets或userConfigPresets
3.2、调用pathToObj方法:将收集的plugin或preset以对象的形式输出
//输入umidev经yargs-parser解析后为://args={ //_:["dev"],//}0umi官网中提到过:每个插件都会对应一个id和一个key,id是路径的简写,key是进一步简化后用于配置的唯一值。便是在这一步进行的处理
形式如下:
//输入umidev经yargs-parser解析后为://args={ //_:["dev"],//}1思考:为什么要将插件以对象的形式进行描述?有什么好处?
执行run方法,初始化插件在Service类实例化完毕后,会立马调用run方法,run()执行的第一步就是执行init方法,init()方法的功能就是完成插件的初始化,主要操作如下:
遍历initialPresets并init
合并initpresets过程中得到的plugin和initialPlugins
遍历合并后的plugins并init
这里的initialPresets和initialPlugins就是上一步收集preset和plugin得到的结果,在这一步要对其逐一的init,接下来我们看一下init的过程中做了什么。
Initplugin
//输入umidev经yargs-parser解析后为://args={ //_:["dev"],//}2这段代码主要做了以下几件事情:
getPluginAPI方法:newPluginAPI时传入了Service实例,通过pluginAPI实例中的registerMethod方法将register方法添加到Service实例的pluginMethods中,后续返回pluginAPI的代理,以动态获取最新的register方法,以实现边注册边使用。
//输入umidev经yargs-parser解析后为:/