Ryuushu

  • Content count

    111
  • Joined

  • Last visited

Community Reputation

43 Excellent

2 Followers

About Ryuushu

  • Rank
    Member
  1. Is there any way to remove the Follower attribute (not component) that was added by inst.entity:AddFollower()?
  2. "stale" items?

    @DarkXero Original problem was items going "stale". First was because of loading/saving (I was doing some weird stuff), then because of moving away instantly. I don't actually save chester, but rather the items it's carrying (storing them inside a special container), then I just save and load the items into chester when needed; putting it inside a cave was no problem. I'm unsure if not letting the items sleep can cause performance issues, and overriding c_gonext in a chester mod feels kind of wrong... What I did to "refresh" the items was to give chester's items to chester when it opens, like so: for k,v in pairs(chester.container.slots) do chester.components.container:MoveItemFromAllOfSlot(k, chester) end This triggers the refresh and so far it works, but I've been looking for a better way to get the items to refresh.
  3. "stale" items?

    @spideswine Ah, you can reproduce it with regular chester. Just put something in it, teleport away with like c_gonext("cactus") and you'll get the same exact result.
  4. "stale" items?

    Welp, loading and saving is working.. but when you teleport with chester with something like c_gonext items become stale again, which is pretty annoying.
  5. Does anyone knows why this happens? Basically, I'm trying to store chester's inventory in a custom component, so that he doesn't drops it on death and can travel to caves. Everything works so far except that whenever chester loads the items in its inventory they look like that. You can't Shift click them and they all look spoiled until you pick them and put them back in the inventory, then they behave as normal. Weird thing is, this doesn't happens when the player is at or near the coordinate 0,0,0, nor does it happens when you host a server without caves. EDIT: Fixed it by adding a 0.1 sec delay before loading items into chester, maybe items needed a tiny bit of time to update.
  6. Is there any way to ignore/bypass the "ERROR: Duplicate anim x in bank x"? I'm using ktools 4.4.4 and that problem is present in a lot of anims. I looked around and it looks like older versions didn't have that problem, but I can no longer find those.
  7. Thanks a lot for your explanation @DarkXero, now it's working (for reals this time). Thank you too @ptr.
  8. @ptr Well, on a first look it worked. It did find the reference to the function.. but when I tried to modify it I realized it it was the one outside the constructor. How can I access the one inside of it? This is what I have now AddComponentPostInit("age", function(self, ...) local fn = UpvalueHacker.FindUpvalue(self._ctor, "OnSetOwner") print("FindUpvalue", fn) -- This prints correctly local function OnSetOwner(...) print("OnSetOwner") -- This doesn't prints return fn(...) end UpvalueHacker.SetUpvalue(self._ctor, OnSetOwner, "OnSetOwner") -- It's doing nothing since it's the one outside the constructor </3 end)
  9. @ptr Ahh, I didn't know that. AddComponentPostInit worked perfectly. Thanks a lot!
  10. @ptr I just tried this AddClassPostConstruct("components/age", function(self, ...) local fn = UpvalueHacker.FindUpvalue(self._ctor, "OnSetOwner") print("This is what I found:", fn) end) And the result I get is "This is what I found: nil". Can you point out what's wrong?
  11. How can I use rezecib's UpvalueHacker util to modify this onAttacked event? local function onAttacked(player, data) ... end ... local SomeComponent = Class(function(self, player) ... player:ListenForEvent("attacked", onAttacked) -- <- event listener I wanna modify end) I just can't figure out the root for the component.. I've tried randomly guessing self.class, self.Class, self.fn, self._ctor but none have worked. Maybe the author can help me on this? @rezecib
  12. Asymmetcrical Character Design?

    @MaiTerra I was poking around a bit more and figured out how to make idles work: --Remember to replace esctemplate with your character's prefab namelocal function ChangeAnim(inst) if inst.prefab ~= "esctemplate" or inst:HasTag("playerghost") then return end local dir = inst.Transform:GetRotation() local camera_rot = GLOBAL.TheCamera:GetHeadingTarget() % 360 print("Camera rotation:", camera_rot) print("Direction:", dir) if camera_rot == 0 or camera_rot == 45 then if dir <= -5 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end elseif camera_rot == 90 or camera_rot == 135 then if math.abs(dir) >= 90 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end elseif camera_rot == 180 or camera_rot == 225 then if dir >= -5 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end else--if camera_rot == 270 or camera_rot == 315 then if math.abs(dir) <= 90 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end endendlocal FRAMES = GLOBAL.FRAMESlocal TimeEvent = GLOBAL.TimeEventlocal function sg_postinit(sg) local old_locomote_event = sg.events.locomote.fn sg.events.locomote.fn = function(inst, data) ChangeAnim(inst) return old_locomote_event(inst, data) end if GLOBAL.TheWorld.ismastersim then local old_fishingcancel_event = sg.events.fishingcancel.fn sg.events.fishingcancel.fn = function(inst) ChangeAnim(inst) return old_fishingcancel_event(inst) end end -- Add/Remove TimeEvents as you see fitting. More TimeEvents = more accurate animations. Less TimeEvents = Slightly better performance. table.insert(sg.states["idle"].timeline, TimeEvent(20*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(30*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(40*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(50*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(60*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(70*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(80*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(90*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["idle"].timeline, TimeEvent(100*FRAMES, function(inst) ChangeAnim(inst) end)) if GLOBAL.TheWorld.ismastersim then table.insert(sg.states["funnyidle"].timeline, TimeEvent(20*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["funnyidle"].timeline, TimeEvent(30*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["funnyidle"].timeline, TimeEvent(40*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["funnyidle"].timeline, TimeEvent(50*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["funnyidle"].timeline, TimeEvent(60*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["funnyidle"].timeline, TimeEvent(70*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["funnyidle"].timeline, TimeEvent(80*FRAMES, function(inst) ChangeAnim(inst) end)) end table.insert(sg.states["fishing"].timeline, TimeEvent(20*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["fishing"].timeline, TimeEvent(40*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["fishing"].timeline, TimeEvent(60*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["fishing"].timeline, TimeEvent(80*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["fishing"].timeline, TimeEvent(100*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["fishing"].timeline, TimeEvent(120*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["fishing"].timeline, TimeEvent(140*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["run_start"].timeline, TimeEvent(1*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["run"].timeline, TimeEvent(10*FRAMES, function(inst) ChangeAnim(inst) end)) table.insert(sg.states["run"].timeline, TimeEvent(20*FRAMES, function(inst) ChangeAnim(inst) end))endAddStategraphPostInit("wilson",sg_postinit)AddStategraphPostInit("wilson_client",sg_postinit) -- Haven't tested it in the client yet.It's more or less the same except this time it hooks into the stategraph. This time it changes the animation as it moves instead changing it only at the start (when the event is received). This also means it's a bit more intensive (still better than DoTaskInTime though). With this the idle animation + rotating camera should work. I'm still unsure about how well it works with clients. Haven't been able to test it myself. Also, this time it goes into modmain, put it anywhere inside it.
  13. Asymmetcrical Character Design?

    @MaiTerra It goes in the character's prefab file, inside master_postinit. Did you remember to load the anim assets? Hmm, posting the crash screen/error line helps too.
  14. Asymmetcrical Character Design?

    @MaiTerra After playing around for a while, it's quite possible, no need to remake all animations from scratch. And it's rather easy. Notice the eye color. Anyways, here's how you do it: First, save your current Spriter project as mycharacter_build_right. The side view will be the side that'll show when your character is facing right. Copy-paste your project folder (Spriter project + images) to a new folder. Then in that new Spriter project modify the side view images to your liking. Don't worry about your character facing right. Save your spriter project as mycharacter_build_left. Let the autocompiler do its job and throw your new anims in your mod anim folder. In your character file add the new anim assets. Now comes the fun part; handling which anim build we should use. We want to use mycharacter_build_right when it's facing right, and mycharacter_build_left when it's facing left. So, when do we know the character has started facing a side? We could use the event "locomote". That event will be sent when the character moves. So, we just add a listener to that event and use a bit of trickery to figure out what direction is the character facing: inst:ListenForEvent("locomote", function(inst) if inst:HasTag("playerghost") then return end local dir = inst.Transform:GetRotation() local camera_rot = TheCamera:GetHeadingTarget() print("Camera rotation:", camera_rot) print("Direction:", dir) if camera_rot < 0 then camera_rot = camera_rot + 360 end if camera_rot == 0 or camera_rot == 45 then if dir <= 0 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end elseif camera_rot == 90 or camera_rot == 135 then if math.abs(dir) >= 90 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end elseif camera_rot == 180 or camera_rot == 225 then if dir >= 0 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end else--if camera_rot == 270 or camera_rot == 315 then if math.abs(dir) <= 90 then inst.AnimState:SetBuild("esctemplate_right") else inst.AnimState:SetBuild("esctemplate_left") end end end)endBasically what we do here is change our images depending on what side the character is facing. This should work relatively well. I haven't tested it with multiple players, but it should play along nicely. Also, there is another problem: The camera can keep rotating and go out of our scope. This should be solved by using the modulo operation ( % ) and then comparing. There might be some small problems with doing an action and then rotating the camera (like fishing), but nothing gamebreaking.