Jump to content

Help making creatures follow while holding an item


Recommended Posts

Ok, so.. I'm finally catching on to the concepts of lua, somewhat, but when I go to actually code my mod, I'm still getting super lost. I want all creatures in the game to become friendly and follow me around while carrying an item I created. I've got the item made and working in-game, and I found the example follow-the-leader mod that hopefully I can use because it does exactly what I want except I want it only to happen while I have my item equipped.

 

I've tried a few ways of connecting the follow-the-leader code to my item, but I really have no idea what I should be doing and nothing is working. Can someone point me in the right direction? Just a little nudge...

 

Also, I wrote Cheerio about permission to use his code from follow-the-leader before I realized it was an "example" mod. I haven't heard back, but I'm assuming this would be ok to use this code in my mod considering it's an example to learn from?

 

 

Link to comment
Share on other sites

Generic ideas of how to go about this:

  • Make the equippable prefab
  • Make a component that handles getting all valid followers in a radius and making them followers. Have it keep track of which followers it is responsible for adding so that it can remove them when the component is turned off
  • Add your "get followers in radius" component to your equippable prefab
  • When the equippable prefab is equipped, turn on the "get followers in radius" component; when it is unequipped, turn off the "get followers in radius" component (which should in turn clear all the followers)
Link to comment
Share on other sites

Generic ideas of how to go about this:

  • Make the equippable prefab
  • Make a component that handles getting all valid followers in a radius and making them followers. Have it keep track of which followers it is responsible for adding so that it can remove them when the component is turned off
  • Add your "get followers in radius" component to your equippable prefab
  • When the equippable prefab is equipped, turn on the "get followers in radius" component; when it is unequipped, turn off the "get followers in radius" component (which should in turn clear all the followers)

 

 

Cool. I think I need to go read more about components then. Thanks again, squeek.

Link to comment
Share on other sites

Just realized that the component would actually be very similar to the TimeOfDaySwitcher component I wrote in this thread (see spoilered code in the linked post), so you can use that as a reference if you'd like.

 

Cool. I'll take a look. What about the follow-the-leader code I mentioned too? Would it be ok to use some of this as well? As you know already, I'm sure I'll analyze the heck out of that and yours and mix and match and add my own, but is this considered "ok" to use code from an example mod made by a dev?

 

 

Oh, and you'd want to persist the table of added followers across saves. To see an example of saving/loading entity references, search for any component that implements the function LoadPostPass.

 

Hadn't even considered that, but yea I'd definitely want it. Glad you mentioned it.

Link to comment
Share on other sites

Cool. I'll take a look. What about the follow-the-leader code I mentioned too? Would it be ok to use some of this as well? As you know already, I'm sure I'll analyze the heck out of that and yours and mix and match and add my own, but is this considered "ok" to use code from an example mod made by a dev?

Yeah, totally. As far as I know, most/all of the mods Cheerio made were for educational purposes and were specifically made with the intention of their code being re-used.

The UpdateFollowTheLeader function is very similar to what you'd want (the usage of tags seems unnecessary to me in your case, though). And instead of using GetPlayer() you'd want to use self.inst.components.inventoryitem.owner to get the player (but it'd be more flexible, as this would allow a non-player to equip the item as well).

Link to comment
Share on other sites

The UpdateFollowTheLeader function is very similar to what you'd want (the usage of tags seems unnecessary to me in your case, though). And instead of using GetPlayer() you'd want to use self.inst.components.inventoryitem.owner to get the player (but it'd be more flexible, as this would allow a non-player to equip the item as well).

 

Letting non-players carry this is another cool idea. So, a couple of curiosity questions...

 

1. Is there any way in Sublime(or any similar program) to specifically search for where a function or table is originally defined/created?

 

2. Do you think the game would lag/crash/freeze at some point if too many followers were on screen at the same time?

Link to comment
Share on other sites

1. Stuff like that would only exist in an IDE, which I've never used for Lua. You can see a list (no clue how complete it is) of IDEs with Lua support here. I usually just do a file search (in Sublime, CTRL + SHIFT + F) for the function name and then search through the results to find the definition, or try to do a search that might be specific to the definition (like for a global function, you could search for "function FuncName"; tables are trickier, but you could try "tablename = {").

2. No clue. Crash? Probably not. Lag? Definitely possible if the numbers get high enough.

Link to comment
Share on other sites

1. Stuff like that would only exist in an IDE, which I've never used for Lua. You can see a list (no clue how complete it is) of IDEs with Lua support here. I usually just do a file search (in Sublime, CTRL + SHIFT + F) for the function name and then search through the results to find the definition, or try to do a search that might be specific to the definition (like for a global function, you could search for "function FuncName"; tables are trickier, but you could try "tablename = {").

 

Ok, I'm going to see if Eclipse can help me. I used it a bit when I messed around with Java. Part of the problem is I can't tell which things are functions and which things are tables. And even thought I'm learning, I just don't know the code well enough to tell which is which unless i flatout see "function AnimState" or "AnimState = {" except I've searched for both of those and no results came up. Maybe it's neither.. hmm..

 

2. No clue. Crash? Probably not. Lag? Definitely possible if the numbers get high enough.

 

I want any creatures encountered with the item to always be friendly, but maybe I can solve this by making followers break off with a quote "Time for dinner!" or something like that.

Link to comment
Share on other sites

Ok, I'm going to see if Eclipse can help me. I used it a bit when I messed around with Java. Part of the problem is I can't tell which things are functions and which things are tables. And even thought I'm learning, I just don't know the code well enough to tell which is which unless i flatout see "function AnimState" or "AnimState = {" except I've searched for both of those and no results came up. Maybe it's neither.. hmm..

AnimState (and Entity, Transform, SoundEmitter, etc) is a special case. It's called userdata, which basically means that it is defined outside of Lua and then imported into the Lua environment (in Don't Starve's case, it would be written in C++).

So, when you call inst.entity:AddAnimState(), it actually runs a C++ function (inst.entity actually holds an Entity userdata, so you're probably calling something like Entity::AddAnimState()) that creates a C++ AnimState object and then adds it to the Lua table of the entity (it puts it in inst.AnimState). Luckily, there are only a few instances of userdata in the Don't Starve codebase (as opposed to things like Garry's Mod, where you deal almost entirely in userdata), but their implementation is obscured and you are only able to use the functions that are specifically imported into the Lua environment (see my complaints about Don't Starve's restrictive userdata here).

To get a list of which functions are available for a given userdatum, you'd have to look at its metatable, like so:

> print( table.inspect( getmetatable( GetPlayer().Transform ), 2 ) ){  __gc = <function 1>,  __index = {    GetFacing = <function 2>,    GetLocalPosition = <function 3>,    GetRotation = <function 4>,    GetScale = <function 5>,    GetWorldPosition = <function 6>,    SetFourFaced = <function 7>,    SetPosition = <function 8>,    SetRotation = <function 9>,    SetScale = <function 10>,    SetTwoFaced = <function 11>,    UpdateTransform = <function 12>,    <metatable> = {...}  },  __tostring = <function 13>}
Unfortunately, userdata in Don't Starve are pretty much entirely undocumented. Some prominent ones that you'll run into: TheSim, Entity, Physics, Transform, Light, AnimState, DynamicShadow, MiniMapEntity, and an absolute ton in various UI widgets

 

I want any creatures encountered with the item to always be friendly, but maybe I can solve this by making followers break off with a quote "Time for dinner!" or something like that.

You'd have to test it to find the upper limit. I'm sure you'd have to accumulate quite a few followers before seeing performance issues.
Link to comment
Share on other sites

AnimState (and Entity, Transform, SoundEmitter, etc) is a special case. It's called userdata, which basically means that it is defined outside of Lua and then imported into the Lua environment (in Don't Starve's case, it would be written in C++).

So, when you call inst.entity:AddAnimState(), it actually runs a C++ function (inst.entity actually points to an Entity userdata, so you're probably calling something like Entity::AddAnimState()) that creates a C++ AnimState object and then adds it to the Lua table of the entity (it puts it in inst.AnimState). Luckily, there are only a few instances of userdata in the Don't Starve codebase, but their implementation is obscured and you are only able to use the functions that are specifically imported into the Lua environment (see my complaints about Don't Starve's restrictive userdata here).

To get a list of what functions are available for a given userdatum, you'd have to look at its metatable, like so:

> print( table.inspect( getmetatable( GetPlayer().Transform ), 2 ) ){  __gc = <function 1>,  __index = {    GetFacing = <function 2>,    GetLocalPosition = <function 3>,    GetRotation = <function 4>,    GetScale = <function 5>,    GetWorldPosition = <function 6>,    SetFourFaced = <function 7>,    SetPosition = <function 8>,    SetRotation = <function 9>,    SetScale = <function 10>,    SetTwoFaced = <function 11>,    UpdateTransform = <function 12>,    <metatable> = {...}  },  __tostring = <function 13>}
Unfortunately, userdata in Don't Starve are pretty much entirely undocumented. Some prominent ones that you'll run into: TheSim, Entity, Physics, Transform, Light, AnimState, DynamicShadow, MiniMapEntity, and an absolute ton in various UI widgets

 

You'd have to test it to find the upper limit. I'm sure you'd have to accumulate quite a few followers before seeing performance issues.

 

 

 

Ah... so it gets even MORE complicated. Damn, and I was really hoping I could learn enough from modding to develop a AAA game all by myself in a couple months and get superbly rich. This just isn't fair.

 

But on a serious note, yeah I'd read that lua was great for.. well I don't know the term, but smooshing different language together and that C++ is a common one. Lol. It's good to know how to get at it though.

 

So, for instance, this has been confusing me in a number of things I'm seeing in the code. Like this line

 

owner.AnimState:Show("ARM_carry")

 

Basically anything where the parameter is a string. I know parameters can be strings but... why is this a string? It seems like this should just be a variable, or a function(which I guess in lua is sort of just another type of variable) but... I think once again I'm seeing the answer as I type the question. Is it filenames or paths that I'm seeing on most of these occasions? Or does it have something to do with it being userdata defined outside of lua?

Link to comment
Share on other sites

So, for instance, this has been confusing me in a number of things I'm seeing in the code. Like this line

 

owner.AnimState:Show("ARM_carry")

 

Basically anything where the parameter is a string. I know parameters can be strings but... why is this a string? It seems like this should just be a variable, or a function(which I guess in lua is sort of just another type of variable) but... I think once again I'm seeing the answer as I type the question. Is it filenames or paths that I'm seeing on most of these occasions? Or does it have something to do with it being userdata defined outside of lua?

This is the trouble with the lack of documenation of the userdata in Don't Starve. The only way to know what the expected parameters of a userdata function are is to look at examples where it's used in Klei's Lua code. The parameter of AnimState:Show is a string simply because that's what is expected by the function. I know very, very little about the art side of Don't Starve, so you'd have to ask someone else about what exactly that string is used for (I'd assume it's a label of a group of animations or something like that).

You also might be misunderstanding what a variable is. A variable is simply a name given to some data. It's not accurate to say a function 'is a type of variable.' A function is a function. A variable can hold a function, but what that means is that you are simply giving a symbolic name to the function data. A variable is not a separate 'type' of data, it is simply a convenience so that instead of keeping track of memory addresses and the size/nature of the data stored there ourselves, we can store that information in a variable and then access it using a symbolic name of our choice.

Some code to illustrate this point:

local a = {}print( type(a) ) -- prints "table"a = function() endprint( type(a) ) -- prints "function"a = "stuff"print( type(a) ) -- prints "string"a = 1print( type(a) ) -- prints "number"
So, you can see the single variable 'a' can store data of multiple different types, but it's still the variable 'a'. What matters is what the value of the variable is, not the variable itself.

Another example:

local a = "something"local function ParameterExample(param)    return a == paramendParameterExample(a) -- returns trueParameterExample("something") -- returns true
This example shows that the name of the variable is also irrelevant. When you compare two variables, you are comparing their values.
Link to comment
Share on other sites

Btw, I read through your post about the complaints with restricted userdata, and quite a bit of the thread. I commented if you want to read it. I've definitely already come across a number of things already that I wish were available. I'm new to all this(the forum, the game itself, and modding), so I hope I didn't overstep my bounds or say something ignorant by my chiming in there.

 

I definitely understand what a variable is, but I think the difference is maybe just semantics to some degree. Part of what I'm going on is that most lua tutorials say that in lua "a function is just another datatype". Some even use the same phrasing that I have in saying "a function in lua is sort of just another kind of variable". To be honest, saying that goes against what I've always known a variable to be since I learned BASIC as a kid. A function actually does something, whereas a variable is just a piece of information stored somewhere and given a name so you can access it. But in some ways, it helps me to think of it that way. A function contains data, and has a name to access that data. But that's just my thing I guess. Not saying anyone else needs to think of it this way.

 

A variable is not a separate 'type' of data

 

 

I didn't mean to imply this is what I think. I probably just said it wrong.

 

From what I can tell, I think a lot of the string parameters that I'm seeing are referring to filenames... image files, scml files, and whatever else. I don't really know how/why this works like it does, but I think that's a lot of it. And I'm sure some are because of userdata that I can't see that I therefore don't understand, and some are just lua functions that require a string.

 

I do really, really hope they keep working with and updating the mod API/tools. Something I think a lot of people would really love is to be able to change the turf. Personally, when I get way further along in learning this stuff, I'd love to make a sci-fi/futuristic mod where it would be really nice to change the turf to something with metal/lasers/glowing lights/etc. Dana was telling me some of the Up And Away people had tried it, but that it took some real know-how beyond the basic mod tools and it was causing some major lag problems that she didn't think they ever figured out.

Link to comment
Share on other sites

i guess all this mess is going from interpretation-like languages

in fact in languages where you need to compile like C/Pascal/assembler you assign a pointer to function aka address in memory where function entrance is exists

 

in lua i guess its same, you assigning a address/index/whatever of function, but not function itself

Link to comment
Share on other sites

I definitely understand what a variable is, but I think the difference is maybe just semantics to some degree. Part of what I'm going on is that most lua tutorials say that in lua "a function is just another datatype". Some even use the same phrasing that I have in saying "a function in lua is sort of just another kind of variable". To be honest, saying that goes against what I've always known a variable to be since I learned BASIC as a kid. A function actually does something, whereas a variable is just a piece of information stored somewhere and given a name so you can access it. But in some ways, it helps me to think of it that way. A function contains data, and has a name to access that data. But that's just my thing I guess. Not saying anyone else needs to think of it this way.

It's definitely semantics. I think what those tutorials might mean is that "function" is a type, just like "number" is a type. Also, Lua's typing system adds some complexity to that. The function type signifies that it's a callable block of code. However, with metatables, you can make anything callable (or, make it so that calling something will get redirected to a separate function). This gets into more advanced stuff, but, for example, you can make a table callable by doing:

 

local mt = {}mt.__call = function(self, ...)   print("Table was called with the parameters:", ...)endlocal tbl = {}setmetatable(tbl, mt)tbl("things", 53, "stuff") -- prints "Table was called with the parameters:    things    53    stuff"tbl("otherthings") -- prints "Table was called with the parameters:    otherthings"
This is pretty unnecessary information for general use but note that this is how creating a Class object is handled:

local SomeClass = Class(function(self) end)print( type(SomeClass) ) -- prints "table"-- 'calls' the table, which redirects to the object instantiation functionlocal SomeObject = SomeClass()

From what I can tell, I think a lot of the string parameters that I'm seeing are referring to filenames... image files, scml files, and whatever else. I don't really know how/why this works like it does, but I think that's a lot of it. And I'm sure some are because of userdata that I can't see that I therefore don't understand, and some are just lua functions that require a string.

I'm not really sure what confuses you about this. Functions like AnimState:Show have to receive some signifier of what to show. It being a string just makes it more intuitive, as the alternative would be a number or some other datatype which wouldn't make as much sense as it's much more descriptive to call AnimState:Show("ARM_carry") than AnimState:Show(1). It also tells you about how other systems go about doing things. If the parameter was a number, that'd mean that the animation system uses numbers as IDs for AnimStates, but you can tell that they use strings instead.

 

I do really, really hope they keep working with and updating the mod API/tools. Something I think a lot of people would really love is to be able to change the turf. Personally, when I get way further along in learning this stuff, I'd love to make a sci-fi/futuristic mod where it would be really nice to change the turf to something with metal/lasers/glowing lights/etc. Dana was telling me some of the Up And Away people had tried it, but that it took some real know-how beyond the basic mod tools and it was causing some major lag problems that she didn't think they ever figured out.

Replacing turf is definitely possible. I'm not sure if the stuttering got fixed, but it's also unclear whether or not the turf was even the direct cause of that. It's a hard bug to test because it's really inconsistent and it really didn't receive all that much testing anyway.

Up & Away is really, really well done (the code can be looked at here). They successfully implemented a ton of stuff that's not really found in other mods (turf replacement, brand new cave-like worlds, totally new worldgen, main menu replacement, worldgen screen replacement, etc, etc, etc). simplex is one of the most competent Lua programmers I've ever seen (his code can go way over my head; see his wicker library) and it's unfortunate that he seems to have gone inactive.

The thing about my complaints with the status of the modding API is not really about what's not currently possible. Almost everything is possible. Very, very little is truly impossible (my Don't Starve modding motto is: "It's probably possible but it might not be easy"). My complaint is more that there is no reason not to address what is currently impossible or broken, especially when you have a community that is willing to point out exactly what that is and help you to fix it. The developers have the opportunity to build a strong and long-lasting modding community and 90% of the work is already done; they just need to invest in the last 10%.

Link to comment
Share on other sites

Oh, and a function does not necessarily have a name. A nameless function is called an anonymous function, and they're used quite frequently:

 

-- this callback function passed to AddSimPostInit is an anonymous functionAddSimPostInit(function(inst) end)-- we do not have a variable that holds the callback function at this point-- the only way to access it would be to get it from the SimPostInit table that it was added to
EDIT: Another example of how functions are just another datatype:

-- this is exactly equivalent to: local FunctionName = function() print("stuff") endlocal function FunctionName()    print("stuff")endlocal var = FunctionName-- var and FunctionName are equal; they both hold references to the same functionlocal isequal = FunctionName == varprint( tostring(isequal) ) -- prints "true"-- we can clear FunctionName and the function will still exist in varFunctionName = nilprint( type(var) ) -- prints "function"
Link to comment
Share on other sites

It's definitely semantics. I think what those tutorials might mean is that "function" is a type, just like "number" is a type. Also, Lua's typing system adds some complexity to that. The function type signifies that it's a callable block of code. However, with metatables, you can make anything callable (or, make it so that calling something will get redirected to a separate function).

 

 

I think most of the tutorials I'm referring to are the "for complete beginners" kind, so I think they are just trying to give new people a way to think about it. And I can admit that it helped me, even though I know it's not really a "variable".

 

I'll definitely refer back to the code examples you gave, but I think they're above my head at the moment, so I wouldn't even know what else to ask about those. I have a tendency to spend way too much time studying and analyzing and not actually *doing*, which I'm pretty sure slows down my learning process. I just get obsessed by understanding every character I type even though that's probably not at all the best way to learn to code.

 

 

I'm not really sure what confuses you about this. Functions like AnimState:Show have to receive some signifier of what to show. It being a string just makes it more intuitive, as the alternative would be a number or some other datatype which wouldn't make as much sense as it's much more descriptive to call AnimState:Show("ARM_carry") than AnimState:Show(1). It also tells you about how other systems go about doing things. If the parameter was a number, that'd mean that the animation system uses numbers as IDs for AnimStates, but you can tell that they use strings instead. 

 

 

I don't really know. I guess when I think of a function receiving a string as a parameter, I think of something that is going to output text somewhere, and I think otherwise it's going to be a variable or another function, etc. I'm starting to get why there are other reasons a string might be used, such as filenames, but it still just throws me off some. I don't know why. The main thing I meant in the last post about being confused though was the functions that accept strings to access filenames. It's when there is no path, just the filename, that I don't understand how it knows where to look for the file. I have a feeling the more I code on my own though, this will become clear.

 

 

 

Replacing turf is definitely possible. I'm not sure if the stuttering got fixed, but it's also unclear whether or not the turf was even the direct cause of that. It's a hard bug to test because it's really inconsistent and it really didn't receive all that much testing anyway.

Up & Away is really, really well done (the code can be looked at here). They successfully implemented a ton of stuff that's not really found in other mods (turf replacement, brand new cave-like worlds, totally new worldgen, main menu replacement, worldgen screen replacement, etc, etc, etc). simplex is one of the most competent Lua programmers I've ever seen (his code can go way over my head; see his wicker library) and it's unfortunate that he seems to have gone inactive.

The thing about my complaints with the status of the modding API is not really about what's not currently possible. Almost everything is possible. Very, very little is truly impossible (my Don't Starve modding motto is: "It's probably possible but it might not be easy"). My complaint is more that there is no reason not to address what is currently impossible or broken, especially when you have a community that is willing to point out exactly what that is and help you to fix it. The developers have the opportunity to build a strong and long-lasting modding community and 90% of the work is already done; they just need to invest in the last 10%.

 

 

My first goal is getting this first mod done, which has turned out to be way more difficult than I thought. If it really is possible to replace turf, maybe I'll try that in the near future after this first mod. Or at least look into the Up & Away threads about it.

 

That definitely sucks if simplex has gone inactive. It was also news to me that Up & Away was kind of on hold right now(which I learned in the other thread you directed me too). I sure hope it eventually gets finished. It looks like an amazing project. I'm surprised to hear you say that simplex's code goes over your head. I've read some of your other posts besides the ones in my threads, and you seem to be quite talented. But I guess being a beginner, I have no idea how complex it can get.

 

As for the mod API complaints, I agree with you in theory. Sometimes things just aren't as easy as they seem though, and even the very informed public can't know exactly what's going on. <--- This might be the case, OR they may just "not feel like it" even though it truly would be easy and not take much time. If it's the first case, I DO think they need to communicate better, and also be more realistic in their goals. In reading various threads you've told me about, and my own bug reports, they could definitely improve the communication. If it's the second case, well then I guess it's their choice, but it definitely just sucks. I still think they are several notches above most studios though from what I've seen so far.

Link to comment
Share on other sites

I'm surprised to hear you say that simplex's code goes over your head. I've read some of your other posts besides the ones in my threads, and you seem to be quite talented. But I guess being a beginner, I have no idea how complex it can get.

The beauty of Lua, and the reason that I enjoy coding in it, is that, at it's core, it's very simple. The actual number of default Lua library functions is incredibly tiny compared to most other programming languages, to the point that it's entirely feasible (I wouldn't say I'm totally there yet, but I might not be too far off) to be familiar/comfortable with 100% of the default Lua libraries. Past that point, it's all just working with what pieces you have to figure out how to put the puzzle together. simplex creates very complex puzzles using the pieces in ways that I don't always understand, but can recognize as incredibly powerful, robust, and flexible. So, while I can understand what the pieces do individually, it may be hard to figure out how they fit together to create a bigger picture, though it has become a lot easier over time (I've learned a ton from reading and trying to understand how his code works).

 

I'm not sure I'm going to talk much more about the situation with the modding API. I've kind of done all I can and said everything I think needs to be said. It's up to the devs to either act or not.

Link to comment
Share on other sites

The beauty of Lua, and the reason that I enjoy coding in it, is that, at it's core, it's very simple. The actual number of default Lua library functions is incredibly tiny compared to most other programming languages, to the point that it's entirely feasible (I wouldn't say I'm totally there yet, but I might not be too far off) to be familiar/comfortable with 100% of the default Lua libraries. Past that point, it's all just working with what pieces you have to figure out how to put the puzzle together. simplex creates very complex puzzles using the pieces in ways that I don't always understand, but can recognize as incredibly powerful, robust, and flexible. So, while I can understand what the pieces do individually, it may be hard to figure out how they fit together to create a bigger picture, though it has become a lot easier over time (I've learned a ton from reading and trying to understand how his code works).

 

Well, I do like the idea of it being a "simple" language so to speak. I had seen it called elegant because of its simplicity, but since you can easily hook it to C++ or whatever else you need to, I guess it can be really powerful too(or whatever the proper way to say "hook it to C++ is). Considering how confused it gets me, it's probably a better language to start with than some others.

 

So now I'm off to create a whole bunch of errors. Lol.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...