Jump to content

tk422

VIP Member
  • Posts

    56
  • Credits

  • Joined

  • Last visited

  • Feedback

    0%

Everything posted by tk422

  1. Ah cool! Thanks for the info on p_state! Do you know what the available states are? I assume: - 0 = Ready - 1 = Busy (Using Skill) Cookie's are like player-properties you can set. They can only hold int values. Cookies are NOT persisted to the database. When the player logs out, they are removed. To SET a cookie: void myself.SetCookie(CSharedCreature* talker, string cookieName, int cookieValue); To GET a cookie: int myself.GetCookie(CSharedCreature* talker, string cookieName); They're great for something like holding a player's choice before promping for some verification. Example: I've written a de-level NPC where players select their desired level but then also must enter their current level as a sanity check and to confirm they REALLY want to do this. Since you can only send back one bit of information from the player's interaction with the NPCs HTML i must get their cookie first, then perform the confirmation. If the conformation goes though, get the cookie and set their desired level. Some additional thoughts: 1. Since a switch case in NASC doesn't provide a default case you often have to rely on fall-through cases. You code could be made more readable / organized like this: switch (reply) { case replyIncorrectChoice1: case replyIncorrectChoice2: case replyIncorrectChoice3: case replyIncorrectChoice4: { myself::Say( "nope"); myself::CreatePrivates( Conversion ); myself::Despawn(); break; // Stops "fall through" } case replyCorrectChoice: { myself::Say( "Correct answer"); break; } } 2.Calculating Rand(10 < 5) a bunch of times takes up handler / CPU time unneccisarily. You only need to do this once. class 1 wiseman : citizen { parameter: int replyFinishedChosing = 1000; handler: EventHandler MENU_SELECTED(talker, ask, reply, fhtml0, i0) { if (reply == replyFinishedChoosing) { // I specified in the handler arguments that i'd like // to use one of the 10 int registers i0-i9; // We can now assign the result of ONE Rand() call to // it and then check that. i0 = Rand(10); if (i0 < 5) { // Reward One } else { // Reward Two. } } }
  2. You sent me a PM but as mcbigmac once asked me, "Why let knowledge die?" :P So want to reply in public for future people who need this information. You asked if i have any account creator which can make you an account to test: Xel (from this forum) makes a terrific tool which can help you: http://www.maxcheaters.com/topic/168444-l2off-gm-panel-v22-new/ As far as which tables are affected: - Lin2Db > user_account - Lin2DB > user_auth If you configure and run Xel's tool you can see what it does and how the tables are manipulated. If you want to write your own tool or account registration system i recommend marking the secret question / answer fields as allowing nulls: http://puu.sh/j8Ssx/6af39a4b89.png You should manage account security / password reset requests some other way. Also note that i changed the width of my password field to binary(20) from binary(16). This means i can use one of the other password algorithms in hAuthD which are easier to work with and are less prone to collisions. If you go to make these changes and get an error, make sure you uncheck the box in options that says "Prevent saving changes that require table re creation". http://puu.sh/j8Sqd/0a18f94167.png (MSSQL Management Studio > Tools > Options) Hope this helps!
  3. Which pack do you use? For AdvExt they have 2 options: 1 - BuffSettings.ini where you can define the list of buffs and macros. Then in your HTML just call the bypass that's listed at the top . 2 - Profile-Based which relies exclusively on a weirdo HTML template system. This is a paid feature. When you buy it they send you the html template that calls the internal extender bits which make it work. Not sure about other packs. You could also make your own buffer. it's just a matter of creating a new NPC and the associated HTML and then writing some small bit of AI to actually do the casting based on what the user selects.
  4. Why they don't / wont provide a working system is beyond me. Did the same thing with interlude. I'd think you need to use L2SystemPatcher (or write a script for L2DisAsm from l2dstuff) then either patch gameguard manually or use a patcher. Or grab the NWindow.dll from a server that has it patched already. Though that's def cheating! :P I've only ever worked with IL but ASSume the process is the same.
  5. Really interesting. Had no idea this was even a thing. So i'm assuming there is a DM table somewhere that you can populate with codes and then define what the rewards are? Then when the code is entered the reward is applied?
  6. Ahh cool! Yah that's an interesting use case. Is that what p_state is? physical state?
  7. The best case scenario would be this: - Write a rest API that runs on the same network as your game server(s) that handles / abstracts the various potentially dangerous tasks. ( Account Creation, Activation, Item Delivery, etc) - Open the port the API runs on to your webserver but set the scope to ONLY talk to your web server's IP. - The web server should only talk to your rest API. Never to anything sensitive. Player > Web Server > API > Scary L2 Shit :P Assuming the API is resilient and secure enough you now have a very minimal attack surface. I wouldn't go crazy with SSL between the API and the web server. No one can touch the traffic anyway ... unless your web server gets haxxed. :D Definitely set up notifications and make sure to keep very comprehensive logs.
  8. Ahh, right that would make sense. I guess the i_ai0 is set for the entire length of the NPC's lifetime versus the i0 register which is only valid during handler execution. Thanks! Yah the incorrect chance i think is to due with using if else statements instead of a switch case. Or even a bunch of If's and then return's. Something like would make more sense. myself.i_ai0 = gg::Rand(5); switch (myself.i_ai0) { case 1: { myself::ShowPage( talker, wiseman_challenge_ ); break; } case 2: { myself::ShowPage( talker, wiseman_challenge_2 ); break; } // blah blah.... } Though TBH i am wondering if this AI would work consistently with more than one player talking to the NPC at once. If the i_ai0 is internal to the instance, one player is going to overwrite the other if two were talking. I'd think this is a good time to use a register or if the value needs to be preserved and accessed later, use a Cookie: myself.SetCookie(CSharedCreature* talker, string cookieName, int cookieValue);
  9. Yah, AI is a bit strange, still learning it myself though could have helped with this if i had seen it sooner. :P Glad you figured it out! I beautified and re-uploaded your code here: http://pastebin.com/LKqgncrn Have some questions about it: - Line 18: What is i_ai0? Just an empty int placeholder in the NPC instance? What's the different between doign this and using one of the registers i0, i1, etc? - Line 65: Why do you assign talker to target? Just for convenience / sanity? - Line 259: What is p_state?
  10. I can't speak for VG pack specifically but you should not need to install any additional roles onto the machine. Just make sure you have all the latest updates and security patches for MSSQL and the OS. MS seems to only release SQL updates purely as service packs so just grab the latest. Install all the .Net's manually though, then just grab the updates and security patches though WU. General security advice: - Disable Windows Firewall and get a real piece of gear to handle protection. Mikrotik is great though there is a bit of a learning curve if you're not familiar with networking. - Block all inbound ports to the server except Auth and L2Server. - Allow RDP access but only from specific IP's. Better yet use NAT to change the port to something silly. - Log all outbound connections from the server. - Do NOT run the registration system on the machine. Run it somewhere else and filter / proxy the connection.
  11. For our NPC Manager we use LightMare's decompiler and then AdvExt's Interlude compiler. I think the compiler was $80 or something but was worth every penny. LM's decompiler lets you send it data though stdin and then responds through stdout which is much faster and less IO than writing / reading files. Thanks LM! Output is always on the standard channel though, errors aren't sent to stderror unfortunately. You have to detect and process them as they happen. This should be rare though. Once you have the entire file decompiled and each class separated, iterate over each one and make whatever modifications required. AdvExt's compiler can compile multiple classes provided you have made the changes described in the included ReadMe. - Remove the gg:: prefix on global calls. gg::Rand() becomes just Rand() - Remove the :: postfix to myself and replace with dot. AKA - myself::Say becomes myself.Say() - Switch statements become select statements (literally just change the keyword switch to select). - Include the correct preprocessor header one line above each class (see ReadMe). - Include all parent, grandparent, great grandparent etc classes all the way up until the root class for anything you compile. - Always ensure everything written out (for both the compiler and then for use by NPCServer) is in grandparent > parent > child order. Hope this helps, Looking forward to your tool!
  12. As far as i know all of the "current" packs require a 64 bit OS. You will not be able to run an L2 server on a 32 bit machine unless it's an older chronicle. You should check the Windows Event Viewer for anything weird and also check Device Manager for any problematic devices. Beyond that i'm not sure how to help.
  13. You can try the version we used to use but it's written in JavaScript for NodeJS. http://puu.sh/iKTJE/2c4fc47a08.zip Does the auth server included in your pack do anything special that hAuthD doesn't? If not, it's really the better and simpler solution... You could also try contacting XeL. His administration panel has an account creator that uses L2Hash. Might be willing to help out or give you the source.
  14. It's far more likely that this is a hardware or driver issue than anything to do with the ISO. You can always check MyDigitalLife Forums though for download links and hashes to official sources if you really think it's the install. What was the last you did that started causing this?
  15. Rather than use L2Hash, use either SHA1 or MD5. This can be changed in hAuthD.ini. While this doesn't directly answer your question it is much easier and also "more secure" in that there are far less collisions. If you go with SHA1 remember to extend the width of the password field to 20 bytes.
  16. An L2 server is made up of a few different parts. - CacheD: Functions as an intermediary between L2Server and the MSSQL database. - AuthD: Authentication server which authenticated client logins. AuthD has been "replaced" by a third party (non-NCSoft) application called hAuthD. - L2Server: The actual game server. - L2NPC: The NPC server responsible for processing NPC >< player interaction. As far as i know all communication for L2 is done purely using TCP sockets. If i had to GUESS why it would be that TCP was easier to work with for something like L2 because it's not exactly "real time". Here is a teriffic article on the subject: http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/ The lifecycle for login goes something like this: - Player types credentials into input boxes on the screen. - Client generates a packet with those credentials and sends them to the auth server. - Auth server validates them, then replies with a list of available game servers. - Client makes a request for the selected game server. - Auth sends back the connection info for the game server. - Client then makes a direct connection to the game server. For more detailed information check out this project: https://code.google.com/p/l2packets/
  17. Sent you a PM. Anyway, Opened a C4 NPC server in Hopper and found these: - int CNPC::HandleEvent(CNPCEvent* pEvent) - void CNPC::Attacked(CSharedCreatureData* spAttacker, int nDamage, int nWeaponClassID, int nSkillNameID, bool bPartyEvent) - CNPCEvent* CNPCEventFactory::CreateAttackedEvent(CNPC* pNPC, CSharedCreatureData* spAttacker , float damage, int nWeaponClassID, int nSkillNameID) I have to guess what happens since i don't quite understand ASM. - When NPC server starts it creates a lookup table in memory of all the NPC's. - As it parses the AI.obj file, for each NPC it reads the AI handlers defined in AI.obj, Attacked, My_Dying, etc. - Those are then turned into CNPCEvent objects and then added to the npc's handler lookup table. - When an NPC is attacked (or whatever) the NPC server checks to see if that event is handled then executes the handler like this->HandleEvent(event); 1. - I'm assuming that the reason the NPC server uses the compiled format is due to speed. - On NPC server boot, when a handler is created according to the behavior defined in NPCData, the AI must be parsed as-is and stored internally as the ASM-like sequence of instructions you see in the "compiled" language. - i'm assuming that the ASM-ish language is faster to parse than something that needs to be jit'd or compiled during NPC server boot. - Also AFAIK NPC's don't exist until a player walks in, all the AI would need to be jit'd which would be a huge pain for situations where there are many different NPC's in one area. 2. - I think i'm somewhat heading in the right direction but none of it answers how to know what handler params are valid. - If i wrote a parser that read through the AI file and make lists of all possible params for a particular handler, could i then assume that if it's used somewhere by some NPC, it's got to be valid always for that handler? - Example: if i find that an ATTACKED handler for one NPC passes the "damage" param and thats it, if i see another NPC that has "damage" AND "attacker" that means the first one COULD ALSO have had "attacker" it just didnt because it wasn't used? - If c1 was passed in for one handler (say My_Dying) but i don't see it for another, can i assume it could have been defined but just wasn't? 3. Are the registers that are passed in (f0, c1, i2, etc) kind of like guaranteed free space for you to work with if you need to store something temporarily? (I think this is what you wrote earlier but i want to be sure) Again, thanks for taking the time to help with this.
  18. Wow, ok really interesting! So for example: handler 1 39 // ATTACKED variable_begin "myself" "_choiceN" "_code" "_from_choice" variable_end When decompiled looks like: (Took this from Frintezza just because it has a lot of handlers to look at) EventHandler ATTACKED() { if( myself.sm.db_value == 1 ) { myself::SetDBValue( myself.sm, 2 ); myself::AddTimerEx( 10000, 1000 ); } } The actual compiled AI handler is sort of saying - "Here are all the registers / vars i'm willing to give you to work with for this handler." - "Whatever AI code you're going to write, it must only take up *this* amount of memory". - "You can reassign them, reuse them, whatever, but you may not have any more ram." 1. Is this somewhat accurate? Looking at the ATTACKED handler for the "warrior" base class: handler 1 807 // ATTACKED variable_begin "attacker" "damage" "f0" "myself" "_choiceN" "_code" "_from_choice" variable_end This has more params passed in. attacker, damage, f0. 2. Why were these not available for Frintezza's ATTACKED handler? 3. I'm assuming f0 = foat register 0? There is also another oddity: In some of the handlers, "gg" is passed in. In others, it's used without being defined as a compiled param or a decompiled one. You can see below that GG is used (i realise this is a comment but you can see it in the decompiled version) class 1 orc : warrior_passive handler 10 289 // MY_DYING variable_begin "always_list" "c1" "code_info" "i9" "last_attacker" "lparty" "member" "random1_list" "target" "myself" "_choiceN" "_code" "_from_choice" variable_end push_event // always_list push_const 688 add push_reg_sp fetch_i push_event // gg <<<<<<<<<<<<<<<<<<< push_const 632 4. Looking at Orc's superclass "warrior" i'm noticing that the MY_DYING handler is defined here too. AND Orc's MY_DYING handler calls super. So is the gg param definition init'd in the super class which is why you can use it in the child? You're basically extending the super handler? 5. Would you say this rule is somewhat accurate: - All "word" params passed in to a handler's arguments like "talker", "myself", "lparty", "member", "target", etc are "living" objects that can be queried / operated on. - All things like c0, f0, i0 are just registers for you to work with. Kind of like CPU registers in real ASM. 6. If you look at the compile at for Imp you can see that i9 has been defined. class 1 imp : warrior_passive handler 10 268 // MY_DYING variable_begin "always_list" "c1" "code_info" "i9" "last_attacker" "lparty" "member" "random1_list" "target" "myself" "_choiceN" "_code" "_from_choice" variable_end Looking at the super classes though the only one that has i-anyhting is warrior, but that only provides i0, and i1. So where are i2 - i8 being used? BTW, Can't thank you enough for taking the time to help with this. Hope im not being annoying, just trying to figure out the system to all this.
  19. Wow, thanks for all the info! LOL at number 1. I meant community documentation, but i guess was a silly question either way. Sorry about that. :P I have have the list of handlers and functions, but its the parameters that i'm not sure about. Example: EventHandler MY_DYING( always_list, code_info, i9, last_attacker, lparty, member, random1_list, target ) always_list = ?? cose_info = ?? i9 = ?? last_attacker = Last player to attack the NPC lparty = Last party to attack the NPC? member = Last member of the party to attack the npc? Doesn't this always equal last_attacker? random1_list = ?? target = The target NPC had when it was killed.
  20. Hello I'm hoping to find someone willing to act as a consultant for my project. The goal is to have a dedicated person i can email or Skype with to answer questions or make suggestions mostly related to AI and more advanced scripting. I'm not looking to annoy or waste anyone's time with silly things like setup or basic administration tasks. I will of course pay you for your time and expertise. By day i work as an IT consultant / programmer and am great at solving problems on my own when given small hints or direction. Sometimes with L2 stuff though it's difficult to find documentation or explanations beyond the basics. Here's an example of the current questions i have: // AI - I found this: http://en.wikipedia.org/wiki/User:Keeper42/Guardex_ai_functions Is there a more complete list or documentation for each functions? - How would i find a list of all the handlers and their associated parameters? - Handlers pass in objects with types like CSharedPartyData, SharedCreatureData and SkillQuestList. How do i figure out what properties are available for each? - Does myself == the NPC who's is executing the AI? Similar to the 'this' keyword in C++ when referencing an instance of the a class? - What is myself.sm? - Is the gg namespace just a pool of global util functions? Is there a list of them? // Scripts In some cases like with Vuku Orc, in NPCData there are multiple parameters set for npc_ai. npc_ai={[vuku_orc];{[MoveAroundSocial]=138};{[MoveAroundSocial1]=138};{[MoveAroundSocial2]=138};{[setHateRace]=@race_elf};{[setHateRaceRatio]=10}} It looks like these are declared in the monster_parameter parent class and that the values are injected at runtime from NPCData. - Is this accurate? If i were to make a new param of type string called "name" and then added {[Name]=ScaryMonster} in NPCData, - Would this work? - Could i then something like myself::Say(Name); ? - What is watch_list.txt for? - What is skill_pch2.txt for? - What is quest_pch2.txt.txt for? Thanks to everyone for their time.
  21. Haven't been updating this post. Should have been.. :P I've figured out how to read the response ok. But now the issue is converting it into the friendly error code. cachedSocket.on('data', function(data) { if (data) { var response = toArrayBuffer(data); var len = response.slice(0,2); var rid = response.slice(0,1); var rs = ''; for (var i = 0; i < ((len[1]-4) / 4); i++) { var read = response.slice(0,4); rs += read[1]; } console.log(rs); } }); rs is undefined at the end of execution and i'm not sure why. I'm getting to the point where i'll pay anyone who can solve this issue lol.
  22. Yah this is exactly what's happening. Ii'm now closing the socket and all is well. My problem now is how to read the result of what CacheD sends back when the packet has been submitted. This is the original function: function CacheDInteractive($buf) { $fp = fsockopen($this->cachedip, $this->cachedport , $errno, $errstr, 5); $rs = ''; if (!$fp) return $this -> fsockerror; $packet = pack("s", (strlen($buf)+2)).$buf; fwrite($fp, $packet); $len = unpack("v", fread($fp, 2)); $rid = unpack("c", fread($fp, 1)); for ($i = 0; $i < (($len[1]-4) / 4); $i++) { $read = unpack("i", fread($fp, 4)); $rs .= $read[1]; } fclose($fp); $result = $this -> socketerrors[$rs]; return($result); } These two calls: $len = unpack("v", fread($fp, 2)); $rid = unpack("c", fread($fp, 1)); + the foor loop are proving problematic. These functions don't exist in JS, so i have to find another solution to do the conversion and then to get the error code. I can read the data sent back from CacheD but each time i get BwA3AQAA which equals 7. Error code 7 is "Char is currently logged in". Somethings weird because this is not the case for the char im testing operations on. THough like i said im not doing the conversion.
  23. I'm actually using Node.JS and Javascript, not PHP. Working on a full REST API. http://pastebin.com/i2ghYYi6 Like i said, the packets all WORK ok. Like they do what they're supposed to without issue. it's just CacheD giving this error with this one. module.exports.configz is what's kicking everything off. (I'm calling this from another file) It generates a packet with the supplied values and then calls the submitPacket function which actually does the submission to CacheD. The other packets i've made work correctly and with no errors, it's just this one. - Update: Found the issue (i think), Working on how to solve it. I'm opening a socket to CacheD and leaving it open. It looks like whatever command i'm sending is getting sent multiple times where it should be sending once and then disconnecting. Working on a fix.
  24. Ahh, ok. Good to know! Many <3's to you! I asked the AdvExt guys and they say that when using their control panel CacheD doesn't give this error. I was sent their packet manipulation scripts as documentation and am using them verbatim. I don't know how their CP doesn't do this unless they aren't changing char name though a CacheD packet. I think that if the packet im sending was "wrong" in some way CacheD would simply reject it. Is this correct? Could this be an issue with a the stored procedure: lin_GetUserDataByCharName?
×
×
  • Create New...

AdBlock Extension Detected!

Our website is made possible by displaying online advertisements to our members.

Please disable AdBlock browser extension first, to be able to use our community.

I've Disabled AdBlock