# MapleStory143 **Repository Path**: wangdiCoding/MapleStory143 ## Basic Information - **Project Name**: MapleStory143 - **Description**: Chinese MapleStory Server Ver.143 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 14 - **Created**: 2022-03-22 - **Last Updated**: 2023-11-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 本源码来自互联网,仅用作学习交流 Chinese MapleStory Server 143 冒险岛服务端143版本 2019-12-27 Here are the WZ files and SQL files you need 服务端链接:(three ways to download) [1]百度云:https://pan.baidu.com/s/1geBb9mz 密码:bhfn [2]Google 云盘(大陆无法访问):https://drive.google.com/open?id=0B9Ls-F4Al3E-T0xobmtkeVVreFU [3]MEGA网盘(大陆部分地区可以访问):https://mega.nz/#!OQBX0ILZ!PP92J-uexcb6ctzEIz14X7AxdfGC3VKRr-GaExBeuHE 不要用自带的exe文件启动服务端,据说这个文件有木马 don't use exe file to start server,maybe this file is not safe 客户端使用的是国服143版本的客户端,自行下载吧,避免侵权 --- ## 为爱发电 第n次捣鼓冒险岛,这明明就是一个吃力不讨好的问题。相比冒险岛而言,技术有一些确是很有趣,冒险岛也是童年的回忆。主要还是想搞懂技术。 ### 目的 这个项目的目的不是分享如何启动一个143的服务器而是希望找到志同道合的朋友,一起玩好143服务器。我也不懂,就懂一些java的东西。很多东西还得摸索和学习。目的搞懂到底是如何交互以及如何修复后台的。**比如职业技能修复、活动修复boss修复等等。**那些脚本、Wz修改的都比较简单,不是我的目的。所以希望有大佬或者感兴趣的朋友带带我或者一起学习。**我是真的觉得这个很有趣!!!**当然大佬都比较高冷,觉得我就像个菜鸡 项目所有的东西都是我在网上找的,而且我亲手操作过一遍。就好像别人搭好的台子,玩出自己想玩的东西, **这篇文章只是分享一下怎么启动143的服务器。使用的资源论坛都有!!!** ### 为什么选择143? 看到论坛上面143服务器的介绍太少了,所以我自己也想尝试一下启动143 听说同步的一些服都是143修复过去的,所以我也想试试,从这里开始。 我也什么都不懂,应该不会被别人利用吧?以下理解都是我从0开始实际操作的 ### 进入正题 只需要三个东西: 1. 后台源码 gitee上搜索 https://gitee.com/enterprises 2. 143客户端,也就是用户端 3. 一个万能登陆器 ### 具体实现步骤 1. 下载源码,idea导包。直接在gitee上搜索 maplestory143就有,这个就是fork过来的。 ![image-20220324200216544](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324200216544.png) 2. 下载这些项目里面介绍的静态文件 ![image-20220324200942486](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324200942486.png) 只需要用到框出来的文件夹 ![image-20220324201045243](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324201045243.png) 3. 按照里面的介绍把wz文件配置了, 把里面的config文件夹、script文件夹放到当前项目文件夹下。一个是配置,一个是脚本。都可以热更新的。 - wz读的是systemProperties,找到项目启动入口直接加入本地放wz文件夹的地方 ![image-20220324200705900](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324200705900.png) 在启动的main方法下添加 > ``` > System.setProperty("wzpath","H:\\play\\source\\wz"); > ``` 或者配置启动参数也可以 -D,但是换个电脑要重新配麻烦。 - config/ scripts我直接拉到项目的根目录了 如下 ![image-20220324201153069](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324201153069.png) 4.修改路径配置,主要是Mysql配置 ![image-20220324201324819](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324201324819.png) 5. 启动一个数据库,本地没有数据库就用里面phpstudy启动。有数据库直接导入项目的数据库sql文件。 数据库文件在哪搞?启动一次phpstudy把里面的数据库导出来就行。 6. 下载一个143的客户端,论坛很多 7. idea启动项目,有启动问题就解决问题,反正我是直接起来了,这里分配给idea启动项目的内存多一点,我给了3g。 > -Xms3072m -Xmx3072m ![image-20220324202514629](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324202514629.png) idea启动后会有一个ui界面,点击一下 ![image-20220324202844174](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324202844174.png) 我嫌太麻烦了直接把这个启动服务端按钮的逻辑添加在main函数后面的代码里面,idea启动就不用再点一次启动服务端了,但是这里有bug不要再点这个按钮就行。 8. 设置环形网卡,我一开始也不懂网上搜一下。其实就是虚拟网卡。目的是给冒险岛Online连接用的。注意和你配的项目里面的ip地址相同,我这里设置的是默认的 ![image-20220324202752426](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324202752426.png) 9. 找一个万能登陆器跳过143的账号登录。论坛、各种qq群也有很多,发放在mapstory.exe同级目录就行。目的是跳过盛大的登陆进入游戏。 10. 点击万能登录器直接启动服务。 ![image-20220324203335710](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324203335710.png) 11. **进入到账号密码登陆页面再用登录器登陆!!!**,不然后续会出问题。我之前就是提前点了导致进入大区就直接闪退了。感觉是网络出问题了或者是ip被ban之类的我也不清楚。 ![image-20220324203711501](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324203711501.png) 账号密码随便填,不存在的自动会创建账户,点击登陆后续就进入游戏了。 **第一次操作成功还有点小激动!!!!!** ![image-20220324203932161](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324203932161.png) 后面就进入游戏,有手就行了。但是有一个问题必会出现。详见下面问题2 ### ### 最后 我还是坚持我的目的,希望把这个端玩好。当然**前路漫漫,用爱发电**!里面的东西太多了慢慢来吧。真希望有人可以相互交流交流!! ### 工具 代码查询 https://mxdweb.com/ 职业代码:https://www.fengyewuyu.com/forum.php?mod=viewthread&tid=141&highlight=%E8%81%8C%E4%B8%9A%E4%BB%A3%E7%A0%81 --- 问题解决汇总 日期:2022 03- 24 1.解决闪退问题参照 https://docs.qq.com/doc/DZmlnd1BSQnd2S0ti 2.java.lang.NumberFormatException: For input string: "2203232321" 时间大于int表示的最大值2147483647 也就是21年47月48日36:47 实际并不存在 修复:先转成long,然后强转成int 方法地址:tools.DateUtil#getTime(long) ![image-20220324205347429](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324205347429.png) 3.修复新手转职飞侠脚本里面是+敏捷 0324 1. 修复飞镖不消耗问题。解析字段找错了,导致逻辑判断一直以为不需要消耗子弹 实际是下面这个字段 ![image-20220324225805535](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324225805535.png) 代码中是这个字段 ![image-20220324225838582](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324225838582.png) 永远都是0 从而导致这个判断错误,我修复了所以是false ![image-20220324230442128](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220324230442128.png) 只是把获取的地方改一下,该读还是要读的 2. 添加1012100.js脚本,弓箭手转职 0510 想修复打怪任务增加怪物 最终找到了是任务没有初始化,导致任务的怪物没有被添加到任务状态中 server.quest.MapleQuest.initQuests ``` PreparedStatement ps = con.prepareStatement("SELECT * FROM wz_questdata"); PreparedStatement psr = con.prepareStatement("SELECT * FROM wz_questreqdata WHERE questid = ?"); PreparedStatement psa = con.prepareStatement("SELECT * FROM wz_questactdata WHERE questid = ?"); PreparedStatement pss = con.prepareStatement("SELECT * FROM wz_questactskilldata WHERE uniqueid = ?");//需要的技能 PreparedStatement psq = con.prepareStatement("SELECT * FROM wz_questactquestdata WHERE uniqueid = ?"); //应该是自己写的补丁数据库 PreparedStatement psi = con.prepareStatement("SELECT * FROM wz_questactitemdata WHERE uniqueid = ?");//通过uniqueid来找需要的item PreparedStatement psp = con.prepareStatement("SELECT * FROM wz_questpartydata WHERE questid = ?");//组队任务 ``` 这些表都没有,只能从079那边拿过来,但是数据需要自己填充的。。。怪不得除了id全是空的。 ![image-20220510224515620](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220510224515620.png) navicat同步结构和数据 ![image-20220510224907620](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220510224907620.png) 需要单独添加一个灯泡字段 ![image-20220510232929176](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220510232929176.png) ![image-20220510234345287](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220510234345287.png) ``` 2022-05-11 00:17:59.242 Send SHOW_STATUS_INFO [0061] (11) Recv to : 飞飞 61 00 01 8D 0A 01 03 00 30 30 34 ``` 已经可以正常的发送了,但是客户端确实没有更新到数据,可能是这个封包和079的已经不一样了,需要修复这个 0511 比较了swordie176的源码发现任务id从short改成了int,发现就可以了,任务可以正常完成了 ![image-20220511195542640](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220511195542640.png) 任务相关表信息 ``` # 任务信息 select * from wz_questactdata where questid = 2701 # 任务需要和获取的东西 select * from wz_questactdata where questid = 2089 # 和actdata uniqueid 关联 物品信息 select * from wz_questactitemdata where uniqueid in (select uniqueid from wz_questactdata where questid = 2089 and name = 'item') # 和任务关联的任务 select * from wz_questactquestdata where QUEST = 2100 # 和任务关联的技能 select * from wz_questactskilldata where uniqueid = 218 # 任务的状态 SELECT * FROM queststatus WHERE QUEST = 2701 # 任务信息 select * from questinfo where quest = 2701 # 任务怪物状态 select * from queststatusmobs ``` 绿蘑菇任务是2701,相关联的信息为 ```sql # request info INSERT INTO `chms`.`wz_questdata`(`questid`, `name`, `autoStart`, `autoPreComplete`, `viewMedalItem`, `selectedSkillID`, `blocked`, `autoAccept`, `autoComplete`, `selfStart`) VALUES (2701, '绿蘑菇通缉牌', 0, 0, 0, 0, 0, 0, 0, 0); # request INSERT INTO `chms`.`wz_questreqdata`(`id`, `questid`, `name`, `type`, `stringStore`, `intStoresFirst`, `intStoresSecond`) VALUES (22728, 2701, 'mob', 1, '0', '1110100', '20'); #act data INSERT INTO `chms`.`wz_questactdata`(`id`, `questid`, `name`, `type`, `intStore`, `applicableJobs`, `uniqueid`) VALUES (7757, 2701, 'exp', 1, 434, '', -1); INSERT INTO `chms`.`wz_questactdata`(`id`, `questid`, `name`, `type`, `intStore`, `applicableJobs`, `uniqueid`) VALUES (7758, 2701, 'item', 1, 0, '', 2001); # item data INSERT INTO `chms`.`wz_questactitemdata`(`id`, `itemid`, `count`, `period`, `gender`, `job`, `jobEx`, `prop`, `uniqueid`) VALUES (9101, 1032003, 1, 0, 2, -1, -1, -2, 2001); ``` 对应的就是这个 ![image-20220511204834435](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220511204834435.png) 最后完成任务 ![image-20220511210031058](https://gitee.com/wangdiCoding/pic/raw/master/2021/image-20220511210031058.png) 总结: 其实就是把questid 改成int传就好了。剩下和079的一样。修复任务绝对是吃力不讨好的事情 --- 0512 修复五转任务 这里涉及到脚本任务的完成,但是脚本任务完成原本的代码实际上并没有任何逻辑,所以要完成任务还是需要wz的任务进行支撑。 一个合理的猜测是脚本任务只能是马上完成的?不能是有过程的? 格兰蒂斯的神秘石任务 数据库添加1463任务的数据即可 ```sql INSERT INTO `chms`.`wz_questdata`(`questid`, `name`, `autoStart`, `autoPreComplete`, `viewMedalItem`, `selectedSkillID`, `blocked`, `autoAccept`, `autoComplete`, `selfStart`) VALUES (1463, '格兰蒂斯的神秘石', 0, 0, 0, 0, 0, 0, 0, 0); # 我添加的是简单老麦的信息 INSERT INTO `chms`.`wz_questreqdata`(`id`, `questid`, `name`, `type`, `stringStore`, `intStoresFirst`, `intStoresSecond`) VALUES (22729, 1463, 'mob', 1, '0', '8880010', '1'); ``` 绯红的神秘石 次元之镜加一个废弃营地 脚本是直接完成了任务,说明这个估计不好修复,我也跳过了 server.maps.MapleSlideMenu.SlideMenu5.TownTeleport 最后一行加 bus(24, "万神殿", 400000000, 0), but(25, "废弃营地", 105300000, 0); --- 然后就是获取神秘球的任务 questId = 1466 添加信息 INSERT INTO `chms`.`wz_questreqdata`(`id`, `questid`, `name`, `type`, `stringStore`, `intStoresFirst`, `intStoresSecond`) VALUES (null, 1466, 'mob', 1, '0', '8641000', '10'); INSERT INTO `chms`.`wz_questdata`(`questid`, `name`, `autoStart`, `autoPreComplete`, `viewMedalItem`, `selectedSkillID`, `blocked`, `autoAccept`, `autoComplete`, `selfStart`) VALUES (1466, '另一种力量,神秘力量', 0, 0, 0, 0, 0, 0, 0, 0); --- 0513 今天看代码发现一个问题,服务端是有处理这个五转获取神秘石任务的,这里代码有问题。直接把这一段删了就好了 ```$xslt server.maps.MapleMap.killMonster(server.life.MapleMonster, client.MapleCharacter, boolean, boolean, byte, int) 。。。 } else if (monster.getId() == 9101083 || monster.getId() == 8880000 || monster.getId() == 8880002) { //麦格纳斯 if (chr.getQuestStatus(1463) == 1) { chr.dropMessage(-1, "由于麦格纳斯死亡时施放出的能量,不再受到古瓦洛的力量的影响。"); MapleQuestStatus quest = chr.getQuest(MapleQuest.getInstance(1463)); quest.setCustomData("001"); chr.updateQuest(quest); } } ``` 把昨天限时任务修复 参考swordie ```$xslt public static OutPacket setQuestTime(List> questTimes) { OutPacket outPacket = new OutPacket(OutHeader.SET_QUEST_TIME); outPacket.encodeByte(questTimes.size()); for(Triple times : questTimes) { outPacket.encodeInt(times.getLeft()); outPacket.encodeFT(times.getMiddle()); outPacket.encodeFT(times.getRight()); } return outPacket; } ``` 改成如下,传入的参数改成秒,脚本默认传入的是毫秒 ```$xslt /** * 更新限时任务 * @param quest * @param time second 需要改脚本传秒数 * @return */ public static byte[] startQuestTimeLimit(int quest, int time) { if (ServerConfig.DEBUG_MODE) { log.trace("调用限时任务"); } MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendPacketOpcode.UPDATE_QUEST_INFO.getValue()); mplew.write(1); mplew.writeInt(quest); LocalDateTime now = LocalDateTime.now(); LocalDateTime end = now.plusSeconds(time); FileTime start = FileTime.fromDate(now); FileTime endTime = FileTime.fromDate(end); // outPacket.encodeInt(getHighDateTime()); // outPacket.encodeInt(getLowDateTime()); FileTime.encode(mplew, start); FileTime.encode(mplew, endTime); return mplew.getPacket(); } // FileTime方法 public static void encode(MaplePacketLittleEndianWriter mplew, FileTime fileTime) { mplew.writeInt(fileTime.getHighDateTime()); mplew.writeInt(fileTime.getLowDateTime()); } ``` --- 0514 学习ida,我也不是很会,也是新手,就来简单学习一下: 在swordie代码中可以看到outbound他都有标注, ```java // CUserLocal::OnPacket EMOTION(685), ``` 在我们maplesotry143找到这个包头 `` // handling.opcode.SendPacketOpcode USER_EMOTION_LOCAL(0x2d4), `` 02d4换算出来就是724 然后在143的idb文件找到这个CUserLocal::OnPacket ```aidl int __thiscall CUserLocal::OnPacket(_DWORD *this, int a2, LPCWSTR lpWideCharStr) { int result; // eax int v4; // ecx char v5; // [esp-1Ch] [ebp-20h] int v6; // [esp-18h] [ebp-1Ch] char v7; // [esp-14h] [ebp-18h] int v8; // [esp-10h] [ebp-14h] int v9; // [esp-Ch] [ebp-10h] int v10; // [esp-8h] [ebp-Ch] int v11; // [esp-4h] [ebp-8h] result = a2 - 724; switch ( a2 ) { case 724: // 这里的名字是我改的 result = USER_EMOTION_LOCAL(this, lpWideCharStr); ``` ```aidl int __thiscall USER_EMOTION_LOCAL(_DWORD *this, _DWORD *a1) { _DWORD *v2; // ST18_4 int *v3; // eax int *v4; // ebx int v5; // eax int v6; // esi unsigned __int8 v7; // al v2 = this; CInPacket::Decode4(a1); v4 = v3; CInPacket::Decode4(a1); v6 = v5; CInPacket::Decode1(a1); sub_1B27EB0(v2, v4, v6, v7); return sub_C2D3B0(1); } ``` 可以看到ida需要两个int 一个 byte,我们143服务端也是这样写好的 ``` public static byte[] getDirectionFacialExpression(int expression, int duration) { log.trace("调用"); MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendPacketOpcode.USER_EMOTION_LOCAL.getValue()); mplew.writeInt(expression); mplew.writeInt(duration); mplew.write(0); return mplew.getPacket(); } ``` 这样就对应上了,这就是一个简单的例子,具体什么意思我也不懂,需要再研究研究 --- 0518 在重构job和skill相关的代码发现好多技能都是两个技能id,但是是同名的,感觉有点离谱,难道是技改了?比如下面这个 ![image-20220518104628604](https://gitee.com/wangdiCoding/pic/raw/master/2022/image-20220518104628604.png) --- 0520 1. 重构攻击的发现里面有079的技能判定删掉了,侠盗的金钱攻击 1. 主要拆分攻击不同的攻击类型 近战、远程、魔法攻击,不同的职业需要单独实现的功能 1. 解析包体 2. 是否显示暴击 3. 控制被动攻击、例如斗气掉点数(原来代码就是写在近战攻击的处理里面) 4. 攻击类 1. 判断攻击怪物数 2. 判断攻击段数 3. beforeAttack(计算实际数值,比如是否对已经有刺客标记的怪物做出响应,或者其他) 4. 判断是否无视反伤 5. onAttack判断攻击应该角色的状态,包括怪物的状态等、 6. afterAttack (攻击完后的状态,比如是否无敌等等) 总结: 1. 主要解耦成以上这几个方面,远程和魔法攻击也是类似,先把所有职业都解耦出来,然后打算再一个一个的修复。后面这几个attack的不同状态,会麻烦一些,而且看完代码发现好多都没有实现的。所以还是慢慢来咯。 2. 还要把状态相关的部分也了解,不然技能感觉也不好修复 3. 主要就三个维度:1.伤害 ,2.不同职业、职业群的效果 3.不同的状态。 职业和状态可能是多对多?