Jump to content

madrussian

Member
  • Content Count

    1025
  • Joined

  • Last visited

  • Medals

Everything posted by madrussian

  1. I've been using trusty old doMove and "PathCalculated" events for ages now. Most of the time this combo works great. Call doMove and then split seconds or a couple seconds later (depending on how far destination is and how complicated the in-between terrain is), "PathCalculated" fires, and we can use this path to do all manner of cool things. However... What about the case where we call doMove and the unit can't get a path? Of course, it must be that unit only tries his path-finding for so long and not forever. Anyway, how do we know when he's actually given up? The big elephant in the room (from my perspective anyhow) is, why don't we have an event for the instant a unit gives up on his path? ^ Alas, no such event exists, and this (determining when path-finding has ceased) is basically what I always supposed moveTo, moveToCompleted, & moveToFailed (& doFSM) are for. Despite vast experimentation, I haven't had a huge amount of luck with these commands in the past (in terms of doing anything useful), aside from using doMove/moveTo together to get units to move when they otherwise wouldn't... which is a wonderful trick btw. Today, un-deterred I'm having another crack at getting to the bottom of all this in some editor tests. Here's what happened so far: Test is pretty simple. I have 8 AI guys in a group, all set to allowDamage false to better observe (because I also wanted to see the effect of AWARE vs COMBAT during all this). Here's my 2-cent understanding of how these moveTo-related commands work (again based on many hours trying various things, also please correct if I've got any of this wrong) : The command moveTo is intended for use in (or at least alongside) an FSM called on a unit via doFSM (not execFSM). The command doFSM is there so we can (temporarily) stop the engine's built-in FSM(s) from messing with units while we work on them. [The engine operates on units via two FSMs, combat and formation. And the one we're mostly concerned with here is the engine's built-in formation FSM. I'm modifying the combat FSM, basically disabling it for the moment (if that's how it works), and thus can tell engine's formation FSM is the one directly moving AIs around, not engine's built-in combat FSM]. So in theory we call doFSM, and for the time being the unit is ours, and we are free to call moveTo on him without interruption. To do all this, of course we need a custom FSM, but it can be a little simple thing with a start node and an end node, and a bit of stuff in between, etc. And the idea is to keep it running for just as long as necessary and then promptly let it end so the game can mess the unit again. So far so good. I would then presume, that upon calling doFSM on our unit, and then inside our running FSM calling moveTo, that moveToCompleted would return true once unit (calculates path, then gets moving, then) gets where he's going. And indeed my tests reveal it actually works this way, which is nice. Meanwhile, I would also presume that upon calling doFSM on our unit, and then inside our running FSM calling moveTo, that moveToFailed would likewise return true at some point, presumably when unit failed to get a path. In my tests however, I've never seen moveToFailed return true, like never ever ever. Indeed, when inside a doFSM I try to send my unit to a known bad place (via moveTo), like inside a giant rock (from not too far away, to ensure whole path would otherwise be calculating + because I know distant units calculate paths in chunks or at least revise paths in chunks as they get closer), & after about 15 seconds, no path has calculated (as expected) but moveToCompleted returns true. Two things are weird about this. First, I expected moveToFailed to return true, not moveToCompleted. And second, that it takes so long (again, ~15 secs). Questions: Has anyone (ever) managed to get moveToFailed to return true? And if so under what circumstance? In cases where moveTo is unable to find a path, is engine really doing it's pathfinding for a full 15 seconds before giving up? (I suppose I would have expected a timeout of like 3-5 seconds tops...) Semi-related - Does anyone understand expectedDestination command return's forceReplan component? Seems like it always returns false for me... If devs happen to be reading, could we get a "PathCalculationFailed" event? Pretty please? Anyhow, I'm sure my tests are not anywhere close to exhaustive. Any insight/discussion is greatly appreciated. 🙂
  2. Quick callExtension question(s), hopefully someone knows. Wiki spells out how much data can be returned from callExtension: My environment scanner uses an extension that is coming up close to this 10240 byte callExtension return limit. As I scan more complicated terrain (etc), I know sooner or later it's going to bust past this limit. I got to thinking, what about Extension Callback event handler? I read through callExtension's Extension Callback section here and didn't see anything specifically about a limit, but it does mention a buffer which at least implies a data limit. (Wiki here also mentions 100 slots per frame, which is related but doesn't directly tell us how much data that Extension Callback buffer can hold.) Questions: Are the "callExtension return buffer" and the "Extension Callback EH buffer" actually different buffers? If so, how big is the Extension Callback EH buffer? (hopefully bigger than 10240 bytes) Any help is much appreciated, many thanks. 🙂
  3. madrussian

    callExtension question(s)

    That's awesome & a great relief, thanks. 👍
  4. madrussian

    SOG AI

    J-boy, every new script and mission you release is a wild ride and a real treat. Fast and fluid own squad AI? Count me in! This is the key to single playing these missions. Your first addon also iirc. There’s so much quality stuff in here. The leapfrogging alone is phenomenal! Dynamic killer tracking dogs?!? I’m starting to wonder if you’re not actually some kind of crazy scripting machine robot, sending us gifts from the future. Fellow single players, our man has really broken through some serious engine-AI boundaries here. Totally worth seeing & trying out for yourselves.
  5. I'm knee deep in development of an AI mod I believe many of you will find truly transformational. Rather than show videos, provide lengthy descriptions, etc, I'd rather simply focus my time moving forward towards completion. Please take me at my word - If I manage to complete everything, the reward will be worth the wait. A very brief description would be - Automatic Navmesh creation (covering entire map) Pathfinder (implemented in C++) Innovative new way to move units around (allowing strafing, etc) Advanced use of Buildings & Cover Here's what will help my effort the most right now: _unit doMovePath _path - Engine will pre-check the user-provided path to see whether engine can perform it (considers slopes, etc). If the path checks out, engine proceeds to move unit along the path using exact same mechanics as doMove. Returns true if it worked and false if not. "PathCalculationStarting" event - Different than existing "PathCalculated" event, as this one happens just prior to the engine's normal path calculating attempt, and gives option to prevent the path calculation from even starting (in other words aborting path calculation), by handler returning false (instead of the normal true). Parameters provide path's intended start and end positions. With these two new capabilities (EH and command), creators could easily intercept engine path creation and substitute in their own highly efficient (C++ produced) paths, saving enormous amounts of CPU and preserving what I like to call precious SQF bandwidth. Curious, how feasible are these and might we see one or both eventually? Quick speculation: Meanwhile, big thanks to the devs (plus anyone else who had a hand) for these absolutely amazing recent AI related (2.10) capabilities: Finally this bit:
  6. Thanks Dedmen for moving thread here (per request). Thanks Harzach for the suggestions. I will file a ticket soon also, just need to figure out how (again). 😉 ^ edited
  7. I'm writing an A3/C++ interface for my (crazy) AI mod, using callExtension. Noticed something that's slowing down my dev effort, namely that as soon as you callExtension on a particular dll file, from that point on that dll file is frozen until the game itself is exited. Meaning that called dll can't be deleted (or thus rapidly replaced). So every time you make a C++ change, unless you go to some extra lengths, you must restart the game to try out changes to your dll. It is of course possible to keep copy/pasting in your new dlls and renaming them (while keeping the game open), and correspondingly change your callExtension calls within A3. Anyway that's super finicky, and I'm wondering if there's a better way. Question #1: Is it possible to tell A3 to release control of a previously called dll? (without exiting game) Meanwhile, I had the idea of having my very basic callExtension dll just call another dll with all my important code in it. My idea is, even if A3 locks down the callExtension dll, maybe other dlls called by that dll remain free for deletion/replacement, etc. I read up on run-time based dlls and set up 3 test projects in VS: One exe and two dlls. Basically my test exe gains access to my 1st dll's function (during runtime). That 1st dll's function then gains access to my 2nd dll's function (during runtime), which returns a result. So on my test exe's console, I see the correct result from my 2nd dll, proving that this mini chain works as expected. (in my test environment anyhow). In this working example, my exe is analogous to A3, my 1st dll is analogous to callExtension dll (which remains locked upon calling), and my 2nd dll is analogous to the dll that we wish to remain unlocked (and thus deletable). Armed with this small victory, I tried to duplicate this result with a new A3 callExtension dll and a separate dll (both containing minimal test code like before). I did everything the exact same way as before (for all practical purposes). Fired up the game and called callExtension. But unfortunately so far, it doesn't work. I can tell based on the callExtension return values (which I set up for various outcomes). Upon investigation, my LoadLibrary call (in my callExtension dll) to my separate dll returns NULL pointer, so I'm stuck there. Question #2: Any particular reason calling LoadLibrary (inside your callExtension dll) to a separate dll shouldn't work? Otherwise, maybe I'm just doing this wrong. In that, case maybe I'll post my simple test code and see if someone can point out the flaw. Question #3: If this idea should work, anyone know if that separate dll will end up "locked" (until game exit) as well, making all this a fool's errand? Anyhow, thanks for reading and thanks in advance for help. 🙂
  8. That sounds splendid, many thanks. 🙂
  9. Thanks, very good to know this definitively. 🙂 I checked out your blog entry. From entry: I'm definitely experiencing pain in the butt from restarting A3 over and over. Your tool dlls look extremely useful, but probably won't help me much in this case, because I'm in-game visually analyzing a bunch of 3D markers generated by my C++ code. So I do need the game up & running, and the actual A3 callExtension dll connected up. Also as you point out in your blog, freeExtension is a command you wish were included in the actual game (but unfortunately isn't). Anyhow, my last two questions stand. I'll re-phrase them a bit to be more specific: 2. If one needs/has actual A3 running and calls callExtension dll (via callExtension command) from A3, is there any particular reason calling LoadLibrary (from within aforementioned callExtension dll C++ code) to a separate dll shouldn't work? ^ Specifically, I'm trying to figure out why my callExtension dll's LoadLibrary call is returning a NULL pointer. (Whereas this very thing works perfectly in my exe -> dll -> dll test code.) Again, I'll post my A3 callExtension code and seperate dll code (and/or my test code too) if someone cares to take a look. 3. If one managed to make this work (see #2, again running actual A3 calling callExtension dll via callExtension command which then calls a 2nd dll via LoadLibrary and GetProcAddress C++ calls), anyone know if that 2nd dll will simply end up "locked" as well? (like callExtension dll always ends up "locked" upon being called 1st time by A3) By "locked" I mean unable to be deleted/replaced until game exit. If that 2nd dll can indeed be called, but is destined to directly end up "locked" too (unable to be deleted/replaced), I might as well just give up on this idea now and try something completely different. My pal @johnnyboy recommended a queue [callExtension dll communicating to/from another app like an exe (console or similar)]. Thanks again for the help. Just trying to figure out how all this works. Also, thanks @killzone_kid generally for your blog. It's helped unstuck me more times than I can count.
  10. Loving many aspects of Reforger so far. However can't jump on board fully yet due to two severe (seemingly related) issues: From normal view (not looking down sights), pressing "Toggle Sights" should result in looking down sights. However roughly 50%, upon pressing "Toggle Sights" I don't end up looking down sights. From sights view, pressing "Toggle Sights" should result normal view (not looking down sights). However roughly 50%, upon pressing "Toggle Sights", I don't end up looking down sights. To summarize, "Toggle Sights" works about 50% of the time, and doesn't work the other 50% of the time. From 1st person, pressing "Change Perspective" should result in 3rd person. However, roughly 50% of the time I don't end up in 3rd person. Likewise from 3rd person, pressing "Change Perspective" should result in 1st person. However, roughly 50% of the time I don't end up in 1st person. To summarize, "Change Perspective" works about 50% of the time, and doesn't work the other 50% of the time. More specifics: In both cases (above), upon pressing the control I can see the camera motion fiddling around a little bit, like it started to switch and just ended up switching back. I made sure that both of these controls are set to exclusive keys, meaning no other controls are set to those same keys. (And obviously these two controls are set to different keys. Also note, when I say "key" I mean key or mouse button.) Either of these problems alone is pretty much a show-stopper. Taken together, they make for a completely maddening experience! Any suggestions?
  11. madrussian

    Controls issue (please help)

    Ok, I had a minute to try Reforger again. I put all controls back to default just for testing purposes, and confirmed that both "Toggle perspective" and "Aiming down sights (toggle)" work as expected. The thing is, I will never play this way. The first thing I do with any new game is go set up my keys. I tried remapping "Toggle perspective" to several other keys (one at a time). All other keys (that I tried) have same original problem (see above), where camera flinches a bit but I only end up actually switching perspective ~ 50% of the time. I tried remapping "Aiming down sights (toggle)" to several other keys (one at a time). All other keys (that I tried) have same original problem (see above), where camera flinches a bit but I only end up actually switching sights aiming perspective ~ 50% of the time. Getting up and running with a new game from an established developer shouldn't be this hard. Imo remapping keys in-game should just work. (I haven't messed with ".chimeraUserImput.conf" yet.) I'm sure I'll love Arma 4 (& maybe Reforger) one day, but right now I'm really regretting this purchase...
  12. madrussian

    Controls issue (please help)

    Yes. Iirc, "Toggle Sights" by default is bound to the same key as another control as well (zoom perhaps?). To help troubleshoot, I rebound "Toggle Sights" and "Change Perspective" to exclusive keys. 99% sure I was having these problems with vanilla key setup too, but I'll double-check. Hopefully no controls in the game are (even halfway) hardcoded, such that certain controls can't be rebound successfully (due to cross-talk, etc). Good info to go on, I'll check this out. Thank you. 🙂
  13. madrussian

    Arma Reforger - Mission Editor

    Has anyone found a list with all Enforce script commands yet? (either online or in-game)
  14. madrussian

    Arma Reforger - Mission Editor

    I like and use Arma 3 editor in 2D mode all the time, and never bother much with 3D editor mode. I create things dynamically (pretty much exclusively) all the time, so don't need that 3rd dimension, except in scripts of course which I go absolutely vector-crazy with. Enjoying Reforger so far, but really missing that editor, which imo should have shipped with the game. As in, seems to me the game should have been held back until at least a 2D editor was ready. But we are where we are so might as well trudge along and make the most of it.
  15. madrussian

    New informations or announcement soon?

    Wow this sounds pretty rough editor-wise... still got my fingers crossed though. I guess it's going to be a while before anyone can say, but I'm really curious how these "simplified AI" (per Drewski's phrasing) hold up for basic infantry combat and path-finding? Also has anyone managed to get an AI into a car to see how he drives?
  16. madrussian

    New informations or announcement soon?

    In my bomb bunker too anticipating exact same words.
  17. madrussian

    AlertAI mini-mod

    I like it... simple & effective! Agree, it's a rather huge shortcoming in vanilla to not have any communication to dudes who are right there standing next to you. (The implementation wasn't simple though, huh?)
  18. Very interesting, didn't realize you started this prior to calculatePath. So glad you followed through and created this. It's quite integral to cases where engine paths won't work, for one reason or another (like inside buildings). In my own experience (perhaps ironically), it is the game engine's calculatePath that could be argued as obsolete. Especially considering the potential for Intercept powered path-finding as it performs so lightning fast, plus ability to provide alternatives to engine path (which can be quite problematic, as anyone who has ever tried to load up squad AIs into own vehic can attest). Another dev request while we're at it: A "CalculatingPath" event, which fires just prior to the path calculation beginning. (May sound counter-intuitive but trust me, this would be a huge gamechanger for calculating engine paths faster, at least in my AI.) ^ Not to be confused with the existing "PathCalculated" event, which fires after the path calculates.
  19. The feeling is mutual. 😉 You've inspired me (and hit my funny bone) more than you can know. Churning out brilliant useful scripts like that. You are quite welcome. Curious on your distance problem (great catch btw), can you just use vectorDistance? I imagine as a game command it's super optimized. Haha, my own code confuses me too & sometimes after I just wrote it. Basically, I'm sending units through buildings using forced movement (like with playAction). With point selection based on "rooms", etc (in far more dynamic way than using buildingPos positions). It's pretty fun and looks great when working properly. Hopefully I can show something off sooner or later. When it stumbles or messes up, it reminds me of when pierremgi called forced movement though buildings a Rube Goldberg machine. Btw - Johnnyboy helped me get my AI force moving, and inspired me big time to get them moving through buildings. As far as I know, he's the forefather of these forced movement techniques. Also, Leopard has helped me big-time getting Intercept up and running. Which can (theoretically) perform path-finding much faster than SQF. One day you guys are going to be pretty shocked by how well AIs are able to fully use buildings, once unleashed using forced movement and pathfinding. It'll come sooner or later. Anyhow, mine's still a good ways off. Long story short I got pretty far, but ultimately may end up being just for personal use... if it can't be made to perform well enough, etc. If any devs are reading this, will you please find a way to enable the "flex" pivot bipod poses for AIs (where AI's gun pivots on a point and AI's feet stretch down to the surface below, like player can do), so AI can make far better use of windows & low walls? I (along with Leopard & no doubt others) will take that capability and run like crazy with it!
  20. I found your bug! (99.9% sure now) ^ This was on the right track, but wasn't quite it. Let's revisit Dijkstra's algorithm real quick from that wikipedia page: In your code, it appears during the part where neighbor nodes are evaluated (in step 3 above), if any neighbor node is the destination node, you're pre-maturely declaring a solution. So the way you've got it works to provide a complete solution (i.e. start to finish), but isn't necessarily the shortest. In fact in my experience, it is often not the shortest. To fix everything up (so it will actually provide shortest possible path), we must instead only check whether current node is the destination node (in step 5 above), and only then declare a solution. I tried to fix yours up, but got confused, so I started over from scratch. Here's a working implementation. Not super optimized (yet), but in my (rather extensive) testing so far, it is always providing the actual shortest path: Hope that somehow helps. 😉 Also btw- They do say this explicitly: So apparently the destination node doesn't technically have to become the current node to declare a solution, provided the other checks are completed. Which is maybe how you were trying to implement? Regardless, hats off to you Sarogahtyp and many thanks for taking on this pathfinding stuff! Your work is incredibly inspiring, and quite integral to much of what I'm working on lately. 🙏 Edit - Corrected edge cases related to connections, made connection distance calcs optional, & streamlined here and there:
  21. Ok, based on some visualization tests, plus some very limited code inspection, it looks like the very first instance of a found solution is returned. Whether or not it's actually the shortest. If this is true and it can be fixed, maybe user can prioritize either first solution found (completing faster) -or- shortest solution found (completing slower), via a function parameter?
  22. Roger, many thanks! Ok in terms of result, seems like I found a way to get it consistently not finding shortest path. I'll dive into the code and have a look for a solution.
  23. Is this known issue "Dijkstra currently not getting always the true shortest path" fixed in any version? If not, any idea where the bug is? I may take a crack at fixing it.
  24. Agree, in terms of needing to define what we're after here. Also thanks you all for helping to focus my efforts. ^ This pretty much sums it up! Lets add one critical detail. After thinking long and hard about the 3ms window... turns out what we really need to measure is actual work done vs expected work done, over a specified number of frames. Specifically, we probably want to avoid constantly looping scripts, spinning away measuring this. Rather we'd like something we can call up on demand, measure quickly (using the absolute least possible amount of CPU), quitting promptly. I whipped up this "SQF load measuring" implementation. Based on limited testing, it appears to be extremely accurate. Have a look, & let me know if I'm simply off my rocker, how this can be improved, etc: MRU_MSQF_Frames = 0; MRU_MSQF_Cycles = 0; MRU_MSQF_Script = scriptNull; MRU_MSQF_RunUntilFrame = 0; MRU_MSQF_EachFrame = { MRU_MSQF_Frames = MRU_MSQF_Frames + 1; if (MRU_MSQF_Frames >= MRU_MSQF_RunUntilFrame) then { terminate MRU_MSQF_Script; removeMissionEventHandler ["EachFrame", _thisEventHandler]; }; }; MRU_MSQF_Monitor = { while {true} do { MRU_MSQF_Cycles = MRU_MSQF_Cycles + 1; sleep 0.001; }; }; MRU_MSQF_MeasureLoad = { private ["_load","_startFrame","_endFrame","_startCycle","_debug"]; params [ ["_overFrames", 21] ]; if (_overFrames < 2) then { _overFrames = 2 }; _load = -1; _startFrame = 0; _endFrame = 0; _startCycle = 0; //_debug = true; isNil { _startFrame = MRU_MSQF_Frames; _endFrame = _startFrame + _overFrames; _startCycle = MRU_MSQF_Cycles; MRU_MSQF_RunUntilFrame = _endFrame max MRU_MSQF_RunUntilFrame; if (scriptDone MRU_MSQF_Script) then { MRU_MSQF_Script = [] spawn MRU_MSQF_Monitor; addMissionEventHandler ["EachFrame", { call MRU_MSQF_EachFrame }]; }; }; waitUntil { isNil { if (MRU_MSQF_Frames >= _endFrame) then { _load = 1 - ((MRU_MSQF_Cycles - _startCycle) / (MRU_MSQF_Frames - _startFrame - 1)); }; //if (_debug and (_load >= 0)) then { // ["MRU_MSQF_Cycles - _startCycle","MRU_MSQF_Frames - _startFrame - 1"] call MRU_SystemChat; //}; }; _load >= 0 }; _load }; To test: MRU_MSQF_MeasureLoad returns SQF load between 0 and 1 over last _overFrames # of frames. With (presumably) quite minimal impact to actual SQF load. Ok, so how does all this works? Let's see... I'm counting work done (MRU_MSQF_Cycles accumulating inside a spawned script) over a specified number of frames. MRU_MSQF_Cycles will accumulate once per frame (and only once), provided it can. If at the end of the specified frames, performed cycles is equal to the frame span - 1, we have (min) 0% load. Alternately, if at the end of the specified frames performed cycles equals 0, we have (max) 100% load. Turns out we must measure over at least 2 frames, because the MRU_MSQF_Cycles won't start counting until the 2nd frame (because script just got spawned). Measuring over 21 or 11 frames works well, because it provides a nice 5% and 10% load result increments. This method of course ignores how SQF load impacts frame rate itself, but for my purposes that turns out to be quite irrelevant. Also note for testing this I settled on simulated load scripts running: while {true} do {}; ^ This (presumably) ensures these test scripts are using their full scheduler time-slice. At any point during the test, feel free to call the following (in the debug console) to see the SQF load drop back down to 0%: { terminate _x } foreach TEST_LoadScripts; TEST_LoadScripts = []; I do wish there was a way to measure SQF load instantaneously, but seems would likely need a new engine command. Dedmen? This looks pretty amazing! Definitely on my list of things to check out. 🙂 Somehow I doubt it provides instantaneous SQF load check. Please enlighten if it does. Also btw - Great discussion everyone. Plenty of good ideas in here.
  25. I'm looking for a way to measure how busy the script engine is at any particular moment (for scheduled code). The best I've come up with so far looks something like this: TEST_Count = 0; TEST_Timer = time + 1; TEST_EachFrame = { if (time > TEST_Timer) then { hint format ["TEST_Count: %1", TEST_Count]; TEST_Count = 0; TEST_Timer = time + 1; }; }; TEST_MonitorBusyness = { while {true} do { TEST_Count = TEST_Count + 1; }; }; addMissionEventHandler ["EachFrame", { call TEST_EachFrame }]; [] spawn TEST_MonitorBusyness; sleep 5; systemChat "Simulating encumbered script engine starting... Now!"; for "_i" from 1 to 10 do { [] spawn { while {true} do { for "_i" from 0 to 1000 do {}; }; }; }; The TEST_MonitorBusyness script above continuously accumulates TEST_Count. Every 1 second, TEST_EachFrame hints a readout of TEST_Count and then resets it to zero. The higher TEST_Count shows, the less busy SQF is (with doing other things). The lower TEST_Count shows, the more busy SQF is (with doing other things). ^ Which makes sense. The more SQF works on other things, the less time it has to accumulate TEST_Count. In this test case, after 5 seconds a higher workload is simulated. Note TEST_MonitorBusyness and the simulated workload below run in an scheduled environments, whereas TEST_EachFrame (as with all EH code), runs unscheduled. See here if unfamiliar. Seems I've achieved the desired goal of measuring SQF busyness. TEST_Count starts out showing ~ 180,000 - 190,000, indicating SQF is not very busy. The moment the simulated workload starts, TEST_Count drops to ~ 13,000 - 19,000, indicating SQF much busier (and remains there). The above however is also imperfect because TEST_MonitorBusyness (again which is doing the measuring) itself is using a huge amount of CPU! The question is thus: How could one go about measuring SQF busyness? Whilst not using much (if any) CPU? ^ Knowing this would greatly help out with some crazy AI I'm working on. Thanks!
×