Jump to content

Konichu

Member
  • Posts

    138
  • Joined

  • Last visited

Everything posted by Konichu

  1. Be careful that Long is a work in progress and hasn't been stressed yet. I'm currently working on Cross Server connections.
  2. I cannot say that it never happened, I had to restart the account server a few times, but it wasnt often. Did you notice if the problem is on the account or game server?
  3. I still cannot see the replies on this topic. Please clean the quotes that are actually too big :/
  4. you found me out xD
  5. Map actions need to be synchronized. Who jumped first? Will it be removed from screen? Are you broadcasting your players movements? If PlayerA leave PlayerB screen by jumping, you remove both from each other visibility dictionary, but you won't "despawn" them from the screen, the client will do it automatically. If you're handling map actions asynchronously without any synchronization, then you'll face this kind of problem. First you need to handle PlayerA movement and then you handle PlayerB movement. First update surroundings and don't broadcast the Walk or Jump packet, send them individually. Whos entering the screen needs to receive your movement packets and who's entering your screen must receive it too. If you broadcast the packet before updating your surroundings, whos in your screen will receive it, but who's entering your screen will not. And if you broadcast them twice, you can guess what will happen. Take a look at this: public async Task UpdateAsync(IPacket msg = null) { bool isJmpMsg = false; ushort oldX = 0; ushort oldY = 0; var dda = new List<Point>(); if (msg is MsgAction jump && jump.Action == ActionType.MapJump) { isJmpMsg = true; oldX = jump.ArgumentX; oldY = jump.ArgumentY; dda.AddRange(Bresenham.Calculate(oldX, oldY, role.X, role.Y)); } else { jump = null; } List<Role> targets = role.Map.Query9BlocksByPos(role.X, role.Y); targets.AddRange(Roles.Values); foreach (Role target in targets.Select(x => x).Distinct()) { bool skipMessage = false; if (target.Identity == role.Identity) { continue; } ushort newOldX = oldX; ushort newOldY = oldY; var isExit = false; var targetUser = target as Character; if (Calculations.GetDistance(role.X, role.Y, target.X, target.Y) <= VIEW_SIZE) // if the target is in my view range { if (Add(target)) // I try to add him to my screen, if I succeed, this means that he is a new entity in my screen, so I'll exchange spawn packets { targetUser?.Screen?.Add(role); // the target must receive me in his screen too if (!isJmpMsg) { skipMessage = true; } if (role is Character user) { await target.SendSpawnToAsync(user); } if (targetUser != null && isJmpMsg) { for (var i = 0; i < dda.Count; i++) { if (targetUser.GetDistance(dda[i].X, dda[i].Y) <= VIEW_SIZE) { newOldX = (ushort)dda[i].X; newOldY = (ushort)dda[i].Y; break; } } await role.SendSpawnToAsync(targetUser, newOldX, newOldY); } else if (targetUser != null) { await role.SendSpawnToAsync(targetUser); } } } else // if he is out of range, I will remove us from each other screen, but won't send the remove packet... { isExit = true; await RemoveAsync(target.Identity); if (targetUser?.Screen != null) { await targetUser.Screen.RemoveAsync(role.Identity); } } if (msg != null && targetUser != null) // in both cases, if the target is a player he must receive my movement packet { if (isJmpMsg && !isExit) { await targetUser.SendAsync(new MsgAction { Action = jump.Action, Argument = jump.Argument, X = newOldX, Y = newOldY, Command = jump.Command, Data = jump.Data, Direction = jump.Direction, Identity = jump.Identity, Map = jump.Map, MapColor = jump.MapColor, Timestamp = jump.Timestamp, Sprint = jump.Sprint }); } else if (!skipMessage) { await targetUser.SendAsync(msg); } } } }
  6. What you need to know is: * If the distance between you and the target is <=18 and he is not added to your screen, you spawn him with the MsgPlayer * If the target distance is >18, you remove him from your screen but DO NOT send the MsgActon RemoveEntity packet, the client will do it alone * You just remove the character from your client screen if he is leaving the map (teleport, disconnect etc) * If you're Moving (MsgWalk or MsgAction:Jump) and the user is in your screen and spawned, you redirect your jump packet to your targets so they know you're moving What the code from my repository does apart from that? Maybe you already notiiced, but when a player enter the screen it will teleport to the target location and that happens because the MsgPlayer will spawn him at the target location already, this will cause that little jump in the same coordinate. Maybe there is an easier solution, but my code calculates the line with Bresenham (Why not DDA? DDA is slower, so for that action I chose Bresenham) and creates a MsgPlayer with the first coordinate in the screen from that line, so when you send the Jump packet after that it wiill jump from the border of the screen at least.
  7. You can take a look at Canyon... never had complaints about this when it was a live server https://gitlab.com/world-conquer-online/canyon/canyon/-/blob/main/src/Canyon.Game/States/World/Screen.cs?ref_type=heads#L64
  8. I tried to add wings as effects once in a lower version too, but the offsets just dont work and idk why.
  9. Patch 5187 is a good version if you want Arena Qualifier, it also have the guild with arsenal and clans. It's clean and imo the best version of conquer.
  10. You don't need to use actions, you can do everything from the LUA Script. If you have the leaked LUAs, there are some functions.. -- 101 Sys_DialogText(sText,nline) -- 102 Sys_DialogOption(sOptionText,strFunc,nAlign) -- 103 Sys_DialogOptEdit(sText,nLen,sFunc,nPassword) -- 104 Sys_DialogFace(nNpcID) -- 105 Sys_MsgBox(sText,sFunc,sFailFunc) -- 120 Sys_DialogEnd(strFunc) -- 123 Sys_ChkFullTime(sParam) -- 124 Sys_PostCmd(nData) -- 125 Sys_NormalBroadcast(sContent) -- 125 Sys_ActionBroadcast(sContent) -- 125 Sys_TeamBroadcast(sContent) -- 125 Sys_SystemBroadcast(sContent) -- 125 Sys_TalkBroadcast(sContent) -- 125 Sys_GmBroadcast(sContent) -- 129 Sys_InviteFilter(nInivteId,sParam) -- 129 Sys_DelInvite(nInivteId) -- 130 Sys_InviteTrans(nMapId,tTransPosx,nStrSendInviteId,nStrTransOKId,nInviteId,nCloseSecs) -- 131 Sys_GotoSomeWhere(nPosX,nPosY,nMapId,nNpcId,nUserId) -- 对应actiontype = 113 -- 清除对话框Task计数 -- 参数1:idUser表示玩家ID, 填0表示自己。如果失败返回false,成功返回true. -- bool MenuTaskClear(UINT idUser); -- Sys_DialogTaskClear() -- #判断是否打开二级密码 -- 对应ACTION:1053 -- LUA接口:IsOpenSecondPWD -- 参数1:玩家id -- 返回值:true表示打开二级密码 false表示没有打开二级密码 -- Sys_IsOpenSecondPWD(nUserId) I'm adding some LUA files here instead of writing to the post. Canyon-lua.zip
  11. Use this snip to set the monster drop. tMonster[3131] = tMonster[3131] or {} tMonster[3131]["tFunction"] = tMonster[3131]["tFunction"] or {} table.insert(tMonster[3131]["tFunction"],Canyon_TitanGanodermaDrop) Examples: ------------------------------------------------------------------------------------ --Name: [Canyon]TitanGanoderma --Purpose: Defines drops for those monsters. --Creator: Felipe Vieira Vendramini --Created: 2023/07/27 ------------------------------------------------------------------------------------ local tTitanGanodermaPotions = {} tTitanGanodermaPotions["2xExpPotion30Min"] = 728775 tTitanGanodermaPotions["3xExpPotion30Min"] = 728776 tTitanGanodermaPotions["5xExpPotion30Min"] = 728777 tTitanGanodermaPotions["5xExpPotion1Hour"] = 728810 tTitanGanodermaPotions["2xExpPotion1Hour"] = 723017 tTitanGanodermaPotions["3xExpPotion2Hour"] = 720393 tTitanGanodermaPotions["5xExpPotion2Hour"] = 720394 function Canyon_TitanGanodermaDrop() local nRate = math.random(1, 100) local nUserId = Get_UserId() if nRate <= 20 then nRate = math.random(1, 100) if nRate <= 15 then -- 15% 5x Monster_SysDropItem(tTitanGanodermaPotions["5xExpPotion2Hour"], nUserId) elseif nRate <= 40 then -- 25% 3x Monster_SysDropItem(tTitanGanodermaPotions["3xExpPotion2Hour"], nUserId) else Monster_SysDropItem(tTitanGanodermaPotions["2xExpPotion1Hour"], nUserId) end else nRate = math.random(1, 100) -- rate for exp potions if nRate <= 7 then -- 7% 5x exp potion 1 hour Monster_SysDropItem(tTitanGanodermaPotions["5xExpPotion1Hour"], nUserId) elseif nRate <= 25 then -- 18 % 5x exp potion 30 min Monster_SysDropItem(tTitanGanodermaPotions["5xExpPotion30Min"], nUserId) elseif nRate <= 50 then -- 25% 3x exp potion 30 min Monster_SysDropItem(tTitanGanodermaPotions["3xExpPotion30Min"], nUserId) else -- 2x exp potion 30 min Monster_SysDropItem(tTitanGanodermaPotions["2xExpPotion30Min"], nUserId) end end nRate = math.random(1, 100) if nRate <= 5 then Monster_SysDropItem(1088000, nUserId) -- drop dragon ball Monster_SysDropItem(1088000, nUserId) -- drop dragon ball Monster_SysDropItem(1088000, nUserId) -- drop dragon ball Monster_SysDropItem(1088000, nUserId) -- drop dragon ball Monster_SysDropItem(1088000, nUserId) -- drop dragon ball elseif nRate <= 20 then Monster_SysDropItem(1088000, nUserId) -- drop dragon ball end end ------------------------------------------------------------------------------------ -- Monster drops ------------------------------------------------------------------------------------ tMonster[3130] = tMonster[3130] or {} tMonster[3130]["tFunction"] = tMonster[3130]["tFunction"] or {} table.insert(tMonster[3130]["tFunction"],Canyon_TitanGanodermaDrop) tMonster[3131] = tMonster[3131] or {} tMonster[3131]["tFunction"] = tMonster[3131]["tFunction"] or {} table.insert(tMonster[3131]["tFunction"],Canyon_TitanGanodermaDrop) tMonster[3132] = tMonster[3132] or {} tMonster[3132]["tFunction"] = tMonster[3132]["tFunction"] or {} table.insert(tMonster[3132]["tFunction"],Canyon_TitanGanodermaDrop) tMonster[3133] = tMonster[3133] or {} tMonster[3133]["tFunction"] = tMonster[3133]["tFunction"] or {} table.insert(tMonster[3133]["tFunction"],Canyon_TitanGanodermaDrop) tMonster[3134] = tMonster[3134] or {} tMonster[3134]["tFunction"] = tMonster[3134]["tFunction"] or {} table.insert(tMonster[3134]["tFunction"],Canyon_TitanGanodermaDrop) tMonster[3135] = tMonster[3135] or {} tMonster[3135]["tFunction"] = tMonster[3135]["tFunction"] or {} table.insert(tMonster[3135]["tFunction"],Canyon_TitanGanodermaDrop) tMonster[3136] = tMonster[3136] or {} tMonster[3136]["tFunction"] = tMonster[3136]["tFunction"] or {} table.insert(tMonster[3136]["tFunction"],Canyon_TitanGanodermaDrop) tMonster[3137] = tMonster[3137] or {} tMonster[3137]["tFunction"] = tMonster[3137]["tFunction"] or {} table.insert(tMonster[3137]["tFunction"],Canyon_TitanGanodermaDrop) ------------------------------------------------------------------------------------ I did this also for CPs/DB drop ------------------------------------------------------------------------------------ --Name: [Canyon]MonsterDrop --Purpose: Defines an interface for all common monsters drop. --Creator: Felipe Vieira Vendramini --Created: 2023/07/17 ------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ -- Parameters -- ItemType: the item type to be dropped -- Money: amount of money to be dropped -- ConquerPoints: amount of Conquer Points to be dropped -- ConquerPointsMono: amount of CPs(B) to be dropped -- MinRate: n in MaxRate -- MaxRate: MinRate in n -- Rate: n in 10000 -- AutoHunt: [boolean] if set means that it will be dropped only on auto hunt or off -- Child: [Object array] -- OpenDate: [yyyy-MM-dd HH:mm] when drop starts -- CloseDate: [yyyy-MM-dd HH:mm] when drop ends -- Message: Valid for parent and child, no args -- ActionLog: Always require two integer args, monsterid and mapid ------------------------------------------------------------------------------------ -- When Child is set Rate will define the coeficient for the drops inside -- Rate inside of a child is the amount necessary for that element -- Example: if main object has 100 MaxRate all Childs must set a Rate, or they wont -- be hit. -- generatedRandom = rand(Parent[MaxRate]) -- if child[Rate] < generatedRandom then drop -- Max depth = 1 ------------------------------------------------------------------------------------ local tCanyonValidMonsterDrops = {} -- [1088000] DragonBall tCanyonValidMonsterDrops[1] = {} tCanyonValidMonsterDrops[1]["ItemType"] = 1088000 tCanyonValidMonsterDrops[1]["MinRate"] = 2350 tCanyonValidMonsterDrops[1]["MaxRate"] = 10200000 tCanyonValidMonsterDrops[1]["Message"] = "You have found a Dragon Ball." tCanyonValidMonsterDrops[1]["ActionLog"] = "%d,%d,1,1088000,2350,10200000" tCanyonValidMonsterDrops[1]["AutoHunt"] = true -- Conquer Points tCanyonValidMonsterDrops[2] = {} tCanyonValidMonsterDrops[2]["ConquerPoints"] = 215 tCanyonValidMonsterDrops[2]["MinRate"] = 2350 tCanyonValidMonsterDrops[2]["MaxRate"] = 10200000 tCanyonValidMonsterDrops[2]["Message"] = "You have found 215 CPs." tCanyonValidMonsterDrops[2]["ActionLog"] = "%d,%d,2,215,2350,10200000" tCanyonValidMonsterDrops[2]["Effect"] = "angelwing" tCanyonValidMonsterDrops[2]["AutoHunt"] = false -- [700001-700061] Common Gems tCanyonValidMonsterDrops[3] = {} tCanyonValidMonsterDrops[3]["MinRate"] = 130 tCanyonValidMonsterDrops[3]["MaxRate"] = 350000 tCanyonValidMonsterDrops[3]["Rate"] = 100 tCanyonValidMonsterDrops[3]["Child"] = {} tCanyonValidMonsterDrops[3]["Child"][1] = {} tCanyonValidMonsterDrops[3]["Child"][1]["Rate"] = 10 tCanyonValidMonsterDrops[3]["Child"][1]["ItemType"] = 700001 tCanyonValidMonsterDrops[3]["Child"][2] = {} tCanyonValidMonsterDrops[3]["Child"][2]["Rate"] = 20 tCanyonValidMonsterDrops[3]["Child"][2]["ItemType"] = 700011 tCanyonValidMonsterDrops[3]["Child"][3] = {} tCanyonValidMonsterDrops[3]["Child"][3]["Rate"] = 30 tCanyonValidMonsterDrops[3]["Child"][3]["ItemType"] = 700021 tCanyonValidMonsterDrops[3]["Child"][4] = {} tCanyonValidMonsterDrops[3]["Child"][4]["Rate"] = 40 tCanyonValidMonsterDrops[3]["Child"][4]["ItemType"] = 700031 tCanyonValidMonsterDrops[3]["Child"][5] = {} tCanyonValidMonsterDrops[3]["Child"][5]["Rate"] = 50 tCanyonValidMonsterDrops[3]["Child"][5]["ItemType"] = 700041 tCanyonValidMonsterDrops[3]["Child"][6] = {} tCanyonValidMonsterDrops[3]["Child"][6]["Rate"] = 60 tCanyonValidMonsterDrops[3]["Child"][6]["ItemType"] = 700051 tCanyonValidMonsterDrops[3]["Child"][7] = {} tCanyonValidMonsterDrops[3]["Child"][7]["Rate"] = 70 tCanyonValidMonsterDrops[3]["Child"][7]["ItemType"] = 700061 tCanyonValidMonsterDrops[3]["Child"][8] = {} tCanyonValidMonsterDrops[3]["Child"][8]["Rate"] = 80 tCanyonValidMonsterDrops[3]["Child"][8]["ItemType"] = 700071 tCanyonValidMonsterDrops[3]["Child"][9] = {} tCanyonValidMonsterDrops[3]["Child"][9]["Rate"] = 90 tCanyonValidMonsterDrops[3]["Child"][9]["ItemType"] = 700101 tCanyonValidMonsterDrops[3]["Child"][10] = {} tCanyonValidMonsterDrops[3]["Child"][10]["Rate"] = 100 tCanyonValidMonsterDrops[3]["Child"][10]["ItemType"] = 700121 -- [1088001] Meteor tCanyonValidMonsterDrops[4] = {} tCanyonValidMonsterDrops[4]["ItemType"] = 1088001 tCanyonValidMonsterDrops[4]["MinRate"] = 500 tCanyonValidMonsterDrops[4]["MaxRate"] = 2700000 tCanyonValidMonsterDrops[4]["ActionLog"] = "%d,%d,4,1088001,500,2700000" -- Conquer Points Bound tCanyonValidMonsterDrops[5] = {} tCanyonValidMonsterDrops[5]["MinRate"] = 43 tCanyonValidMonsterDrops[5]["MaxRate"] = 15450 tCanyonValidMonsterDrops[5]["Rate"] = 100 tCanyonValidMonsterDrops[5]["Child"] = {} tCanyonValidMonsterDrops[5]["Child"][1] = {} tCanyonValidMonsterDrops[5]["Child"][1]["Rate"] = 25 tCanyonValidMonsterDrops[5]["Child"][1]["ConquerPointsMono"] = 1 tCanyonValidMonsterDrops[5]["Child"][1]["Message"] = "You`ve found 1 CP(B)." tCanyonValidMonsterDrops[5]["Child"][1]["ActionLog"] = "%d,%d,5,1,1,43,15450,25" tCanyonValidMonsterDrops[5]["Child"][2] = {} tCanyonValidMonsterDrops[5]["Child"][2]["Rate"] = 50 tCanyonValidMonsterDrops[5]["Child"][2]["ConquerPointsMono"] = 3 tCanyonValidMonsterDrops[5]["Child"][2]["Message"] = "You`ve found 3 CPs(B)." tCanyonValidMonsterDrops[5]["Child"][2]["ActionLog"] = "%d,%d,5,2,3,43,15450,50" tCanyonValidMonsterDrops[5]["Child"][3] = {} tCanyonValidMonsterDrops[5]["Child"][3]["Rate"] = 75 tCanyonValidMonsterDrops[5]["Child"][3]["ConquerPointsMono"] = 5 tCanyonValidMonsterDrops[5]["Child"][3]["Message"] = "You`ve found 5 CPs(B)." tCanyonValidMonsterDrops[5]["Child"][3]["ActionLog"] = "%d,%d,5,3,5,43,15450,75" tCanyonValidMonsterDrops[5]["Child"][4] = {} tCanyonValidMonsterDrops[5]["Child"][4]["Rate"] = 100 tCanyonValidMonsterDrops[5]["Child"][4]["ConquerPointsMono"] = 7 tCanyonValidMonsterDrops[5]["Child"][4]["Message"] = "You`ve found 7 CPs(B)." tCanyonValidMonsterDrops[5]["Child"][4]["ActionLog"] = "%d,%d,5,4,7,43,15450,100" -- FireOfHell tCanyonValidMonsterDrops[6] = {} tCanyonValidMonsterDrops[6]["ItemType"] = 1060101 tCanyonValidMonsterDrops[6]["MinRate"] = 43 tCanyonValidMonsterDrops[6]["MaxRate"] = 750000 tCanyonValidMonsterDrops[6]["ActionLog"] = "%d,%d,6,1060101,43,750000" -- Bomb tCanyonValidMonsterDrops[7] = {} tCanyonValidMonsterDrops[7]["ItemType"] = 1060100 tCanyonValidMonsterDrops[7]["MinRate"] = 43 tCanyonValidMonsterDrops[7]["MaxRate"] = 450000 tCanyonValidMonsterDrops[6]["ActionLog"] = "%d,%d,7,1060100,43,450000" local tCanyonValidMonsterTypeIds = { 1, -- Pheasant 2, -- Turtledove 3, -- Robin 4, -- Apparition 5, -- Poltergeist 6, -- WingedSnake 7, -- Bandit 8, -- Ratling 9, -- FireSpirit 10, -- Macaque 11, -- GiantApe 12, -- ThunderApe 13, -- Snakeman 14, -- SandMonster 15, -- HillMonster 16, -- RockMonster 17, -- BladeGhost 18, -- Birdman 19, -- HawKing 20, -- TombBat 55, -- BanditL97 56, -- BloodyBat 57, -- BullMonster 58, -- RedDevilL117 59, -- RockMonsterL15 64, -- HeavyGhostL23 65, -- WingedSnakeL28 66, -- BanditL33 67, -- FireRatL38 68, -- FireSpiritL43 69, -- MacaqueL48 70, -- GiantApeL53 71, -- ThunderApeL58 72, -- SnakemanL63 73, -- SandMonsterL68 74, -- HillMonsterL73 75, -- RockMonsterL78 76, -- BladeGhostL83 77, -- BirdmanL88 78, -- HawkL93 79, -- BanditL98 80, -- TombBatL103 81, -- BloodyBatL108 82, -- BullMonsterL113 83, -- RedDevilL118 84, -- Banditti 120, -- ElfApe 121, -- SlowApe 122, -- SnakeMonster 1400, -- HugeSnake 1401, -- BanditLeader 1402, -- HugeSpirit 1403, -- CateranSoldier 1404, -- SeniorCateran 1405, -- CateranLeader 1406, -- ChiefCateran 1407, -- HugeApe 1408, -- SeniorApe 1409, -- AlienApe 1410, -- SeniorSnakeman 1411, -- Serpent 1412, -- SeniorSerpent 1413, -- AlienSerpent 1414, -- Basilisk 2410, -- SerpentEnvoy 2411, -- IcySerpent 2412, -- SerpentLord 2413, -- SerpentKing 2414, -- FrostSerpent 2415, -- BladeDevilEnvoy 2416, -- IcyBladeDevil 2417, -- BladeDevilLord 2418, -- BladeDevilKing 2419, -- FrostBladeDevil 2460, -- DarkLady 2461, -- DarkElf 2465, -- NightmareLady 2466, -- GrottoLady 2473, -- SnakeChief 2474, -- SnakeHubbub 2478, -- HeadlessGeneral 2479, -- HeadlessSoldier } local tCanyonMonsterDropLogFilename = "lua_monster_drop" function Canyon_MonsterDropRegister() for index, value in pairs(tCanyonValidMonsterTypeIds) do tMonster[value] = tMonster[value] or {} tMonster[value]["tFunction"] = tMonster[value]["tFunction"] or {} table.insert(tMonster[value]["tFunction"],Canyon_MonsterDrop) end end function Canyon_MonsterDropContainsMonster(nMonsterType) for index, value in pairs(tCanyonValidMonsterTypeIds) do if value == nMonsterType then return true end end return false end function Canyon_MonsterDrop() local nMonsterId = Get_MonsterType() local nUserId = Get_UserId() if type(nMonsterId) ~= "number" or nMonsterId <= 0 then Sys_SaveAbnormalLog("Canyon_MonsterDrop called by a non monster") return end if not Canyon_MonsterDropContainsMonster(nMonsterId) then return end for i, v in pairs(tCanyonValidMonsterDrops) do if Sys_Random(v["MinRate"], v["MaxRate"]) then if v["Child"] ~= nil then if v["Rate"] == nil or type(v["Rate"]) ~= "number" or v["Rate"] < 2 then Sys_SaveAbnormalLog(string.format("Canyon_MonsterDrop invalid rate [%s] for child [%d]!", v["Rate"], i)) else local nLocalRate = math.random(1, v["Rate"]) for localIndex, localValue in pairs(v["Child"]) do if nLocalRate < localValue["Rate"] then if Canyon_MonsterDropExecute(localValue, nUserId) then if v["Effect"] ~= nil then User_EffectAdd("self", v["Effect"]) end if localValue["Effect"] ~= nil then User_EffectAdd("self", localValue["Effect"]) end if localValue["Message"] ~= nil then User_TalkChannel2005(localValue["Message"]) end if localValue["ActionLog"] ~= nil then Sys_SaveActionParamLog(tCanyonMonsterDropLogFilename, string.format(localValue["ActionLog"], Get_MonsterType(0), Get_MonsterMapID(0))) end end return end -- leave Canyon_MonsterDropExecute(localValue) end -- leave local for end -- end child drop rate else if Canyon_MonsterDropExecute(v, nUserId) == true then if v["Effect"] ~= nil then User_EffectAdd("self", v["Effect"]) end if v["Message"] ~= nil then User_TalkChannel2005(v["Message"]) end if v["ActionLog"] ~= nil then Sys_SaveActionParamLog(tCanyonMonsterDropLogFilename, string.format(v["ActionLog"], Get_MonsterType(0), Get_MonsterMapID(0))) end return end -- leave Canyon_MonsterDropExecute end -- leave child if end -- leave sys random if end -- leave for end -- end function function Canyon_MonsterDropExecute(v, nUserId) if v["AutoHunt"] ~= nil and type(v["AutoHunt"]) == "boolean" then local isAutoHunting = IsAutoHangUp(0) if v["AutoHunt"] == false and isAutoHunting == true then return false end end if v["Money"] ~= nil and type(v["Money"] == "number" and v["Money"] > 0) then User_AddMoney(v["Money"]) return true end if v["ConquerPoints"] ~= nil and type(v["ConquerPoints"] == "number" and v["ConquerPoints"] > 0) then User_AddEMoney(v["ConquerPoints"]) return true end if v["ConquerPointsMono"] ~= nil and type(v["ConquerPointsMono"] == "number" and v["ConquerPointsMono"] > 0) then User_AddEMoneyMono(v["ConquerPointsMono"]) return true end if v["ItemType"] ~= nil and type(v["ItemType"]) == "number" and v["ItemType"] > 0 then if v["ItemTypeMode"] == nil or v["ItemTypeMode"] == "drop" then Monster_SysDropItem(v["ItemType"], nUserId) return true else if nUserId ~= nil and type(nUserId) == "number" and nUserId > 0 then Item_AddNewItem(v["ItemType"], "", nUserId) return true end end end return false end tServerStart["tFunction"] = tServerStart["tFunction"] or {} table.insert(tServerStart["tFunction"],Canyon_MonsterDropRegister)
  12. Probably your Conquer.exe is wrong and is crashing because the injected addresses dont match. I think that the address in the repository are for the 6135 client, I am making a commit to update with 6192 addresses. Also they're not complete, they will bug transformations and a few meshes and need to be sorted for a solution, but you'll be able to login. https://gitlab.com/world-conquer-online/canyon/dragon/-/commit/f9122b199791d387f4cc175d507795a09873e1b0
  13. I think it also originated from EO Source EO source is almost CO source with a lot of commented code (and it must be the same for almost every TQ game)
  14. This is what I saw about it
  15. What exception is being thrown?
  16. I'm working on a simplified version that I'm also trying to improve some stuff. It'll see sunlight soon and I'll replace the links in the main post. It's not that I don't want to create a guide on how to setup stuff, but I tried to record a video and it took me more than 1 hour of explanations... then my wife just entered the room screaming because of a bug and I deleted it.
  17. I am reworking the game source code using same base and code but simplifying things. There is no tutorial on this source to avoid leechers to create scam servers with this. This source still need work and has some incomplete features but I believe it's pretty stable and works perfectly with official stuff (LUA and DB), I provided a lot of stuff that even incomplete would be enough for scammers to create servers easily, so I will not provide a guide for this. Even for me it takes some time to setup hosting environments, and I say this because I had to setup a US server after couple months of my BR one. Don't get me wrong, but after the first complete setup you'll see how it's easy to work on Canyon.
  18. Just define the preprocessor variable USE_MYSQL_DB https://gitlab.com/world-conquer-online/canyon/canyon/-/blob/main/src/Canyon.Login/Sockets/Login/Packets/MsgAccount.cs?ref_type=heads#L21 Just add a try/catch block to avoid logins getting stuck if DB is not online https://gitlab.com/world-conquer-online/canyon/canyon/-/blob/main/src/Canyon.Login/Repositories/AccountRepository.cs?ref_type=heads#L7
  19. You need to debug this yourself, check if the player data is being transferred between both servers, which packet has been sent/recv last and track if it was a login, game or network issue. And also make sure that your realm is properly set up on your database. You need to register your new realm, if you need to see how it's done just take the Piglet repository and see the realm management page.
  20. I'll PM you later with a 7117 LUA and database.
  21. No, Canyon has been used in a live server that reached over 180 concurrent accounts. But I may take a look into it soon, I've been working on some stuff lately and haven't been developing Canyon.
  22. I actually develop on a retail 6192 client...
  23. I think that this will have the missing structures. cq_6135_full_structure.rar
  24. I would always recommend at least 2 threads, separate PvP and PvE maps so monsters wouldn't lag event maps, but that was not an issue with many threads. No thread got stuck because of monster AI queueing actions, you can of course test it with 1 thread and it may work pretty well, games worked single threaded for ages with thousands players + mobs and for Conquer it ofc wont be an issue. I do local tests with 3 threads and someday I will do a stress test on this setting as well, my current stress test setting is with 3 to 6 threads.
  25. Depends on how you handle AI. On Canyon I iterate through all agents even if they're not active, that's not a smart idea if you want to do AI checks. You need to queue anything that will change collections, and that's basically it. You of course must test, but I would do AI checks on a separate thread and then just queue actions (move, attack, heal, etc).
×
×
  • Create New...