Page 2 of 4 FirstFirst 1 2 3 4 LastLast
Results 11 to 20 of 38

Thread: Questions about function fallbacks and chaining to generics

  1. #11
    Basic Member
    Join Date
    Nov 2015
    Posts
    108
    Any specific examples you can provide? I thought you were using bot_botname.lua total control? I'm strictly speaking about the default mode-overrides. In the mode-overrides, like you said, it uses the generic function fine if you don't define the over-load in the hero file.

    The problem is that it doesn't recreate the file so anything outside of functions, say the requires at the top of the file aren't run for that bot IF that bot has a hero specific version of that file but they ARE if they do not have a hero specific version (or if they are the first bot to need the generic whether they have a hero specific file or not which is very confusing). Making it a consistency issue. I'm simply asking if Valve intends this to be how it works. If it is, I will probably scrap my current plans and move way from mode-overrides for a system like you are using.
    Last edited by ironmano; 02-10-2017 at 03:28 PM.

  2. #12
    Basic Member
    Join Date
    Mar 2012
    Posts
    2,013
    His first version was sort of a combination between hero+generic, while using OOD for instance related code. That meant generic code could be used with parameters to differentiate between each instance.

    Also note, if you have a shared file, but using different instances, using a local variable is similar to a static one, meaning, it's the same one in every instance.

    I had an experiment of using, sort of a "brain" for each bot (as to use generics, not heroes, but use the brain as instances). Each hero file would spawn the brain. Slight overkill, I know, but it was a PoC.
    Anyway, inside the brain I had a local variable that pointed to the hero class name (GetBot():GetUnitName()) for some fast array access in cached hero handles (back when you could save the enemies too). Since my bots were going haywire I started debugging it and kept avoiding the variable for hours until I logged it and it had the same hero class name for all 5. Once I used member variables in an OOD approach even though that class was a base class that never had any children, the problem was solved.

    Chris solved this by offering hero vs generics, with hero files holding what my brain object would hold.

    Normally, in full takeovers you won't need generics anyway. As for mode takeovers, your best bet is to use parameters. So instead of doing this:

    Code:
    function blah ()
    bot_generic.blah();
    end
    You could try

    Code:
    function blah ()
    bot_generic.blah(GetBot());
    end
    ... assuming you hold all your instance code inside the bot handle.
    As for non-implemented heroes, the only clean way I can think of making it happen is to have an array (basically a table) inside the generic, assigning each slot using the team member functions and working with GetUnitName() or GetPlayerID().

    It's not the best method, but it can help separating handles. There might be more efficient ways, this is just one that came into mind on the spot.
    Quote Originally Posted by ironmano View Post
    Why does it work this way? I can't find any way to make this system work as intended except the dreaded copy/paste in which case why even have a generic file?
    LUA was not designed with OO in mind. It's a procedural language. Recent changes made it bindable and able to simulate a pseudo-OOP approach as stated earlier. But that's it.

    Remember old first-person-shooters ? I mean "old" as in 80s, not as on 2000. Those old DOS games were written in C (not C++) and they had a lot of entities to keep track of. Without OOP. So it's deffo doable. It's just harder without a good design
    In C most did it using structs. In LUA you have tables.

    But I repeat, these are just things that came off the top of my head. Prolly better way out there...
    Explanations on the normal, high and very high brackets in replays: here, here & here
    Why maphacks won't work in D2: here

  3. #13
    Basic Member
    Join Date
    Nov 2015
    Posts
    108
    When you say shared file you are referring to files 'shared' using the require() or getfenv() methods LUA uses as sort of library implementations correct? In my experience I've only seen "using a local variable is similar to a static one, meaning, it's the same one in every instance" to be true in two situations, using the shared file as a library with require()/getfenv() or when you use a generic/hero file combo the way you describe your "brain" PoC. Forgive me if I'm misunderstanding what you mean as a shared file.

    When I have a file that is reused by the bot system multiple times like for example any Meepo file, or any hero file if you have more than 1 of that hero (illusions count as well) in that game. They become separate instances of the file with completely independent variables. Files used as libraries with require() will act as shared single instance files. However, generic will be an independent instance for any hero with no hero file but will act as a shared instance for heroes with hero files. This difference in generic implementation between heroes with/without a hero file is why I'm asking, is this working as intended. All I'm really look for is an answer to that, is this how it's going to continue to work or is this currently bugged.

    Yes, your right I could do all of my init work in a function called conditionally from the overridden Think() and store all instance code in the bot handle and I'd be around this problem. I'd just rather ask this question now when the API is being fleshed out and have a solid answer now in case this isn't the intent of this system. I feel if generic always acted as an independent instance regardless or hero file or not it would be considerably more useful.

    Also, thanks for the continued discussion. I do enjoy learning from all the other projects on here, especially with LUA as I like many others began learning LUA with the release of custom games and then started really using it with bot API. Oh, and yes, I do remember the shooters from the 80's fondly, wouldn't have gone to early 2000's at the word 'old'

  4. #14
    Basic Member
    Join Date
    Mar 2012
    Posts
    2,013
    Quote Originally Posted by ironmano View Post
    When you say shared file you are referring to files 'shared' using the require() or getfenv() methods LUA uses as sort of library implementations correct? In my experience I've only seen "using a local variable is similar to a static one, meaning, it's the same one in every instance" to be true in two situations, using the shared file as a library with require()/getfenv() or when you use a generic/hero file combo the way you describe your "brain" PoC. Forgive me if I'm misunderstanding what you mean as a shared file.
    Actually you understood it correctly 100%. But my brain PoC used require() and OOD. So it's the first scenario you describe.

    Quote Originally Posted by ironmano View Post
    When I have a file that is reused by the bot system multiple times like for example any Meepo file, or any hero file if you have more than 1 of that hero (illusions count as well) in that game. They become separate instances of the file with completely independent variables. Files used as libraries with require() will act as shared single instance files. However, generic will be an independent instance for any hero with no hero file but will act as a shared instance for heroes with hero files. This difference in generic implementation between heroes with/without a hero file is why I'm asking, is this working as intended. All I'm really look for is an answer to that, is this how it's going to continue to work or is this currently bugged.
    Only Chris can reply here. From my POV it's working as intended, but he'd know the design better than anyone

    Quote Originally Posted by ironmano View Post
    Yes, your right I could do all of my init work in a function called conditionally from the overridden Think() and store all instance code in the bot handle and I'd be around this problem. I'd just rather ask this question now when the API is being fleshed out and have a solid answer now in case this isn't the intent of this system. I feel if generic always acted as an independent instance regardless or hero file or not it would be considerably more useful.
    Assuming I am right and you are wrong, then the team member functions are your only solution. If you're right and it gets fixed, then the problem is solved by default

    Quote Originally Posted by ironmano View Post
    Also, thanks for the continued discussion. I do enjoy learning from all the other projects on here, especially with LUA as I like many others began learning LUA with the release of custom games and then started really using it with bot API.
    No worries. AFAIK nostrademous has the most xp with LUA between the 3 of us (not sure about Platinum). I started LUA as soon as Chris released the bot API. I'm mostly into C++, Java and C#, but I always wanted to learn it and postponed it for years. So I figured - why not. As far as design and development goes, since I am learning by doing and testing the boundaries of LUA (remember, I am coding it C++, or better said, C# style since we don't have pointers ) I am still deleting/rewriting the design to suit my needs. This is one of the reasons I didn't post any github yet since the source is not even a draft, let alone an alpha. While I do the micromanagement and focusing on useless and pointless things, I take advantage of it to create a standardized way of implementing my bots. I haven't really thought of a combo-wombo yet, but atm I picked WK, Lina, LC and Lich. That'll prolly change at some point. Unfortunately LUA isn't C# so it has its limitations, but with some proper architecture workarounds and tricks (I am still clinging to best practices where possible, I REALLY REALLY HATE HACKS AND HARDCODING stuff), but it got to a way that I find acceptable
    Now comes the hard part: getting the bots to do what I need. Since this is at the beginning the first step - is of course, getting the starting runes, atm without items (yes, I am THAT far behind)

    The main reason is cos while I do look at some of the bots that get regularly updated (unfortunately, not that many apart from nostrademous, furiouspuppy and thepianodentist I think) for ideas, but it's mostly for the ideas, as I try to think of other ways to write the code, simply to get an idea on how to do stuff from scratch and recycle only utility functions that might prove useful (and maybe optimize them). While reinventing the wheel is slightly pointless, it helps me understand this better

    Nostradmeous' package is probably the most advanced at the moment (not sure about others), so I need to catch up. Then, maybe, I can give his bots a run for their money, but at the moment, those are just fantasies

    Quote Originally Posted by ironmano View Post
    Oh, and yes, I do remember the shooters from the 80's fondly, wouldn't have gone to early 2000's at the word 'old'
    Doom, Wolf and the good ol' Duke Nuk'em 2D (true DN2, is a scroller, not a FPS, but it still owned)
    Explanations on the normal, high and very high brackets in replays: here, here & here
    Why maphacks won't work in D2: here

  5. #15
    Basic Member
    Join Date
    Dec 2016
    Posts
    731
    Sorry I am really low on time and the posts are rather long so I'm regretfully falling into the camp of TL;DR. Can you make a simple example of what you would like to do in pseudo (or real) code that currently doesn't work for you so I can quickly grasp it?

    What "I THINK" you want is to be able to have a mode_attack_bloodseeker.lua that inherits from mode_attack_generic.lua "ALL VARIABLES and FUNCTIONS" and is able to "MODIFY/SET/UPDATE the VARIBALES" in a "PERSISTENT" manner that affect "ONLY THAT HERO" and not the other heroes. Correct?

  6. #16
    Basic Member
    Join Date
    Nov 2015
    Posts
    108
    Quote Originally Posted by nostrademous View Post
    Sorry I am really low on time and the posts are rather long so I'm regretfully falling into the camp of TL;DR. Can you make a simple example of what you would like to do in pseudo (or real) code that currently doesn't work for you so I can quickly grasp it?
    No problem I appreciate the time, but I'm on my phone in the mountains. I'll get one when I get home if you still need it.

    Quote Originally Posted by nostrademous View Post
    What "I THINK" you want is to be able to have a mode_attack_bloodseeker.lua that inherits from mode_attack_generic.lua "ALL VARIABLES and FUNCTIONS" and is able to "MODIFY/SET/UPDATE the VARIBALES" in a "PERSISTENT" manner that affect "ONLY THAT HERO" and not the other heroes. Correct?
    Nailed it. This is what I'd like.

  7. #17
    Basic Member
    Join Date
    Nov 2015
    Posts
    108
    Quote Originally Posted by The Nomad View Post
    As far as design and development goes, since I am learning by doing and testing the boundaries of LUA (remember, I am coding it C++, or better said, C# style since we don't have pointers ) I am still deleting/rewriting the design to suit my needs. This is one of the reasons I didn't post any github yet since the source is not even a draft, let alone an alpha. While I do the micromanagement and focusing on useless and pointless things, I take advantage of it to create a standardized way of implementing my bots. I haven't really thought of a combo-wombo yet, but atm I picked WK, Lina, LC and Lich. That'll prolly change at some point. Unfortunately LUA isn't C# so it has its limitations, but with some proper architecture workarounds and tricks (I am still clinging to best practices where possible, I REALLY REALLY HATE HACKS AND HARDCODING stuff), but it got to a way that I find acceptable
    Now comes the hard part: getting the bots to do what I need. Since this is at the beginning the first step - is of course, getting the starting runes, atm without items (yes, I am THAT far behind)
    I am in a similar position, writing and re-writing sections of code, always finding a better way as I learn what I'm doing in Lua. I had written (or started to anyway) a custom game earlier to see what LUA was like but lost interest until I saw the bot API. The only reason I put out a public GitHub so soon was because I thought I'd built an interesting piece of the early puzzle in a functional jungling Meepo others might want to look at to get ideas or to see one approach or even what not to do's. Anyway my learning hours could benefit others was a win for me even if someone just told me it was bad and do it this other way was fine.

    Quote Originally Posted by The Nomad View Post
    The main reason is cos while I do look at some of the bots that get regularly updated (unfortunately, not that many apart from nostrademous, furiouspuppy and thepianodentist I think) for ideas, but it's mostly for the ideas, as I try to think of other ways to write the code, simply to get an idea on how to do stuff from scratch and recycle only utility functions that might prove useful (and maybe optimize them). While reinventing the wheel is slightly pointless, it helps me understand this better

    Nostradmeous' package is probably the most advanced at the moment (not sure about others), so I need to catch up. Then, maybe, I can give his bots a run for their money, but at the moment, those are just fantasies


    Doom, Wolf and the good ol' Duke Nuk'em 2D (true DN2, is a scroller, not a FPS, but it still owned)
    Yeah, I am always browsing around others projects mainly to shore up my Lua knowledge and see how others implement stuff that I don't know how to do. For example I first learned OOP could be done in Lua from Nostrademous' project. I haven't found a place to use it in a mode-override setup yet, especially if I can use generic/hero the way that I want. However it gave me a great idea for another feature I might try and do someday that would need it.

    Also, my project isn't super up-to-date right now because I was half-way through re-writing how I handle enemy hero handles after the illusion/enemy handle destruction changes when I found the issue that spawned this thread. So as soon as I get an answer or some guidance as to how to solve this issue in a way I am comfortable pursuing I will go update it (I am FuriousPuppy). I find it interesting all the different routes that are being pursued. I agree Nostrdemous' project is one of the bigger undertakings making progression publicly, but then he does have several contributors. I was going to port my Meepo bot over to his but it's hard to find the time to work both when we are taking opposite approaches. Especially as I'm already working my public repo and a private repo with a different approach. I really like the mode-override approach in concept. It got me to a functional point so much faster just because of being able to reuse code for logic like last hit / deny that valve already does pretty well. I am really hoping to be able to finish my approach using mode-overrides it all hinges on generic/hero either working well or someone being able to explain to my dense self how to do it right

    And yeah, I played Duke2D a bit, but I was more a Warcraft Orcs and Humans guy back then.
    Last edited by ironmano; 02-11-2017 at 08:51 PM.

  8. #18
    Basic Member
    Join Date
    Dec 2016
    Posts
    731
    Quote Originally Posted by ironmano View Post
    No problem I appreciate the time, but I'm on my phone in the mountains. I'll get one when I get home if you still need it.


    Nailed it. This is what I'd like.
    If that's what you want it is doable with the current setup although it will be a bit clunky. It would be a lot easier if they gave you an accessor function to the "self" that has all the mode-based functions. What I mean by this is that in our hypothetical mode_attack_generic.lua there is a "function Think()". Doing what you want would be a lot easier if it was a "function parent:Think()". What you will have to do is bastardize all those functions (meaning "OnStart()", "OnEnd()", "GetDesire()" and "Think()" by doing something like this:

    Code:
    local X = {}
    
    function X:new(o)
        o = o or {}
        setmetatable(o, self)
        self.__index = self
        return o
    end
    
    function X:OnStart()
        <WRITE MY OnStart() CODE HERE using self: for all other functions I call in this file>
    end
    
    function OnStart()
        X:OnStart()
    end
    and repeat that for all 4 functions.

    Then in your hero-specific mode-attack instantiation you would do:

    Code:
    local generic = require( GetScriptDirectory().."/mode_attack_generic" )
    
    local derivedBot = generic:new()
    
    function derivedBot:new(o)
        o = o or generic:new(o)
        setmetatable(o, self)
        self.__index = self
        return o
    end
    
    local botInstance = derivedBot:new{} -- not a typo, you want {}
    
    function OnStart()
        botInstance:OnStart() --  <-- this will call the generic (unless you define it in this file) but pass your hero-specific "self" to the generic so it's variables/members are affected
    end
    
    function botInstance:OnStart() -- <-- only include this if you don't want to use the generic implementation 
        <WRITE YOUR HERO OVER-LOAD OnStart() HERE IF YOU HAVE ONE, DELETE THE FUNCTION IF YOU DO NOT>
        < EXAMPLE CODE BELOW TO CALL/REFERENCE THE GENERIC IF WE WANT >
        generic.<WHATEVER FUNC NAME>(self, <OTHER PARAMETERS>) -- the '.' is important since it allows you to pass the real "self". If you did ":" instead it would still work but all variable mods would affect the generic class and not your botInstance instantiation
    end
    Anyways. I have not tested the above. It should work in theory. Be mindful I am a bit buzzed and it's late.
    Last edited by nostrademous; 02-11-2017 at 09:09 PM.

  9. #19
    Basic Member
    Join Date
    Dec 2016
    Posts
    731
    By the way, I started learning Lua same time you guys did so I am sure my understanding of many things is wrong. Just last night I learned some peculiar and unexpected things about tables and the # operator.

    For example:
    Code:
    local a = {action="Move", arg1=loc}
    print(#a)
    Will print 0

  10. #20
    Basic Member
    Join Date
    Nov 2015
    Posts
    108
    Ah yes, only numeric index counts for # I ran into that as well.

    There is also some issue with tables with nil in the middle of them, I cant remember what it is off the top of my head.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •