Replies: 27 (Who?), Viewed: 19112 times.
Page 1 of 2
Mad Poster
Original Poster
#1 Old 28th Jan 2012 at 5:11 PM
Default Custom Buffs
I want to add a custom Moodlet to my mod.

I've been looking at Twallan's WooHooer, and Velocityrass' instructions. I know what I'm suppose to do, but not sure how to do it.

My question is, how do I add a new buff to the sDictionary,

Code:
GenericManager<BuffNames, BuffInstance, BuffInstance>.sDictionary.Add((ulong)guid, value);


When the sDictionary is protected, and can't be accessed.
Advertisement
Top Secret Researcher
#2 Old 28th Jan 2012 at 8:27 PM
The Sims 3 Scripting Core is operated by a MONO interpreter, which does not do any access-level permission checking at run-time.

Because of this quirk you can actually compile your mods against custom Core dlls that have different access-levels than the files used by the game itself.

So, what most of us do is the following :
1) Export the Core S3SA dlls to file
2) Decompile them using ILDASM
3) Change the permissions to "public" (I simply run a script that changes them all, but you only need to change the ones you require)
4) Recompile the files using ILASM
5) Use the altered version of the Core dlls to compile your scripting

You don't have to include the altered Core files in your mod package, since all you are changing is access-level permissions, and the MONO interpreter does not check those anyways.

You can read more about it in this thread, where everyone tries to explain it to jtravers88 : http://www.modthesims.info/showthread.php?p=3360427


NRaas Industries: Sims 3 Mods for the Discerning Player, hosted by The Wikispaces.
Mad Poster
Original Poster
#3 Old 28th Jan 2012 at 9:07 PM
Forum Resident
#4 Old 29th Jan 2012 at 6:17 AM
Twallan, is that script to change access permissions available for download?

I'd like to change permissions in the assemblies I'm compiling against, without
having to change them manually.
Top Secret Researcher
#5 Old 29th Jan 2012 at 5:52 PM
Code:
using System.IO;
using System.Text.RegularExpressions;


Code:
            List<Tuple<string, string>> regEx = new List<Tuple<string, string>>();
            regEx.Add(new Tuple<string, string>("(\\s)assembly(\\s)", "$1public$2"));
            regEx.Add(new Tuple<string, string>("(\\s)family(\\s)", "$1public$2"));
            regEx.Add(new Tuple<string, string>("(\\s)private(\\s)", "$1public$2"));
            regEx.Add(new Tuple<string, string>("(\\s)sealed(\\s)", "$1"));
            regEx.Add(new Tuple<string, string>("(\\s)initonly(\\s)", "$1"));
            regEx.Add(new Tuple<string, string>("\\.field (|static )assembly", ".field $1 public"));
            regEx.Add(new Tuple<string, string>("\\.method public hidebysig specialname instance void(\\s*\\n\\s*add_)", ".method private hidebysig specialname instance void$1"));
            regEx.Add(new Tuple<string, string>("\\.method public hidebysig specialname instance void(\\s*\\n\\s*remove_)", ".method private hidebysig specialname instance void$1"));
            regEx.Add(new Tuple<string, string>("\\.method public hidebysig newslot specialname virtual(| final)(\\s*\\n\\s*instance void  add_)", ".method private hidebysig newslot specialname virtual $1$2"));
            regEx.Add(new Tuple<string, string>("\\.method public hidebysig newslot specialname virtual(| final)(\\s*\\n\\s*instance void  remove_)", ".method private hidebysig newslot specialname virtual $1$2"));
            regEx.Add(new Tuple<string, string>("\\.method public hidebysig specialname static(\\s*\\n\\s*void  add_)", ".method private hidebysig specialname static$1"));
            regEx.Add(new Tuple<string, string>("\\.method public hidebysig specialname static(\\s*\\n\\s*void  remove_)", ".method private hidebysig specialname static$1"));

            string contents = null;

            try
            {
                Application.UseWaitCursor = true;

                using (StreamReader file = new StreamReader(filename))
                {
                    contents = file.ReadToEnd();
                }

                foreach (Tuple<string, string> value in regEx)
                {
                    Regex regex = new Regex(value.Item1);

                    contents = regex.Replace(contents, value.Item2);
                }

                using (StreamWriter file = new StreamWriter(filename))
                {
                    file.Write(contents.ToCharArray());
                }
            }
            finally
            {
                Application.UseWaitCursor = false;
            }

NRaas Industries: Sims 3 Mods for the Discerning Player, hosted by The Wikispaces.
Forum Resident
#6 Old 30th Jan 2012 at 1:01 AM
Thank you so much!
1978 gallons of pancake batter
#7 Old 31st Jan 2012 at 6:37 PM
@ani_: You may want to take a look at BuffManager.CreateBuffTable() and how it loads the buffs for the store objects. Imitating that is the way to go IMHO.

If gotcha is all you’ve got, then you’ve got nothing. - Paul Krugman
Theorist
#8 Old 1st Mar 2012 at 5:13 PM
I'd like to learn how to add custom moodlets too. To imitate the way store objects load buffs, do I need to duplicate CreateBuffTable() into my own project and change the hash instance name from buffs_store to a custom one?

Twallan, does your script need to be compiled for .NET Framework 4? When I try it in VS.NET 2008, it doesn't recognize Tuple and Google search pulls up an MSDN page that says it's for .NET Framework 4.

Resident wet blanket.
1978 gallons of pancake batter
#9 Old 1st Mar 2012 at 6:25 PM
Quote:
Originally Posted by GnatGoSplat
I'd like to learn how to add custom moodlets too. To imitate the way store objects load buffs, do I need to duplicate CreateBuffTable() into my own project and change the hash instance name from buffs_store to a custom one?
Right on. I just whipped that together as a reference. Call the Init method from the static constructor of your mod. My way to initialize and call that stuff is different, but the content from LoadBuffData and AddBuffs is right from one of my mods.

Code:
public static void Init()
{
    LoadSaveManager.ObjectGroupsPreLoad += new ObjectGroupsPreLoadHandler(LoadBuffData);
}
private static void LoadBuffData()
{
    this.AddBuffs(null);
    Sims3.UI.UIManager.NewHotInstallStoreBuffData += new Sims3.UI.UIManager.NewHotInstallStoreBuffCallback(this.AddBuffs);
}
private static void AddBuffs(ResourceKey[] resourceKeys)
{
    ResourceKey key = new ResourceKey(ResourceUtils.HashString64("YOUR_XML_NAME_HERE"), 0x0333406C, 0x0);
    XmlDbData data = XmlDbData.ReadData(key, false);
    if (data != null)
    {
        BuffManager.ParseBuffData(data, true);
    }
}

If gotcha is all you’ve got, then you’ve got nothing. - Paul Krugman
Top Secret Researcher
#10 Old 1st Mar 2012 at 7:51 PM
Quote:
Originally Posted by GnatGoSplat
Twallan, does your script need to be compiled for .NET Framework 4? When I try it in VS.NET 2008, it doesn't recognize Tuple and Google search pulls up an MSDN page that says it's for .NET Framework 4.


It is an application external to Sims 3, so it is not restricted to a specific version in the same way mods are. So, yes I build it using the most up-to-date version of .NET.

Tuple is a simple class to construct yourself though, if you so choose.

NRaas Industries: Sims 3 Mods for the Discerning Player, hosted by The Wikispaces.
Lab Assistant
#11 Old 2nd Mar 2012 at 6:10 AM Last edited by misukisu : 2nd Mar 2012 at 4:06 PM.
Twallan, huge thanks for sharing your script and explaining how to access private fields! I've been struggling with this same problem too.


EDIT: And it works like a charm! I've so been in need of this.
Theorist
#12 Old 2nd Mar 2012 at 2:23 PM Last edited by GnatGoSplat : 2nd Mar 2012 at 8:53 PM. Reason: Got the script to work
Buzzler, thanks, it's good to know my thought process is on the right track.

Twallan, I got the script to work, had to make a Form for it and add an open file dialog. Thanks for sharing it! I don't know C# or OOP at all so the learning curve is pretty steep for me, so I'm pretty happy about even figuring out how to make that script work!

EDIT: Can't hardly believe it, but I got it to work! Got a clean compile thanks to Twallan's script. I don't have any code to trigger it yet, but I can add my moodlet to the sim using Master Controller. I noticed the store items use filetype of BUFF instead of _XML. I can't tell by the code that it matters what filetype I use as long as it matches what the function is looking for. Since I had originally copy and pasted that function and just changed it in my DLL, I left the type as BUFF. Is there any compelling reason to use one vs the other?

Resident wet blanket.
Don't ask me, I just code
DELETED POST
17th Mar 2012 at 12:19 PM
This message has been deleted by pljones. Reason: Hm, didn't work.
Don't ask me, I just code
#13 Old 17th Mar 2012 at 2:44 PM Last edited by pljones : 9th Jan 2013 at 10:31 PM. Reason: Migrtion to Simlogical
Here's a little program to make this even easier. MOVED!! - see below

Drop a .Net DLL onto the .exe and it'll disassemble it, unprotect it and reassemble it "in place" (taking a backup).

It has prerequisites of ILDASM and ILASM.

Source included in the .7z for those interested.

Thanks to Twallan for the method of unprotecting.

---
This tool now has a proper home, rather than hiding here in this thread. It has joined the various other sims3tools hosted over at Simlogical: here!
Forum Resident
#14 Old 3rd Apr 2012 at 9:15 PM
Thank you very much for this thread everyone, it has been extremely helpful.

Ok I have a problem I can't seem to resolve.

I got Velocitygrasses naked toilet mod to work, so my general setup seems to be valid.
.
However, when I unprotect the SimIFace.dll using pljones .exe I get 1 error saying
'Sims3.SimIFace.World' does not contain a definition for 'OnWorldLoadFinishedEventHandler' D:\Documents\Visual Studio 2010\Projects\usetoiletnaked\VelocitygrassSims3Test\test_code.cs 31 19 VelocitygrassSims3Test

What's going on there? I'd like to access private methods in SimIFace but that's no fun when the eventhandler does'nt work Why would the compiler not find it when the dll is unprotected?
Field Researcher
DELETED POST
4th Apr 2012 at 5:55 PM
This message has been deleted by Odistant. Reason: Better explanation by twallan
Top Secret Researcher
#15 Old 5th Apr 2012 at 7:08 PM
You should be careful using my approach on SimIFace.

The regular expressions I use presume there are equivalent member fields for each delegate event, and proceeds to hide all the add_ and remove_ functions to prevent name conflicts.

In the case of OnWorldLoadFinishedEventHandler(), it is hidden in favor of using sOnWorldLoadFinishedEventHandler directly, which may conflict with existing coding.


NRaas Industries: Sims 3 Mods for the Discerning Player, hosted by The Wikispaces.
Forum Resident
#16 Old 6th Apr 2012 at 11:57 PM
@twallan
Uhm thanks for your explanation but I'm afraid I'm too dumb to understand what your'e saying

You're saying you are intentionally hiding the OnWorldLoadFinishedEventHandler with your script and it's fine to use sOnWorldLoadFinishedEventHandler instead?
Forum Resident
#17 Old 3rd May 2012 at 3:25 PM Last edited by nonamena : 7th May 2012 at 6:51 PM.
Thanks to this excellent thread I've made progress towards adding custom moodlets to my custom food mod, but I'm still not quite there. I'm able to get the script to compile, but my own custom moodlets aren't showing up. They are not even being loaded into the game (couldn't see the with MasterController). I've tried both velocitygrass' method and Buzzler's method, and I've looked at Woohooer as well. I think I'd like to use Buzzler's method/store method, because it seems the easiest, if I can get it to work. My quetsions follow, but I'm such a beginner at this they might not even make sense. If that's the class, I apologize.

1. Regarding Buzzler's/Store method, if I'm using this with a object scriptmod, do I still need to call the init method from the static constructor? Can I just create a new class to imitate CreateBuffTable() ?
2. EA's Store buffs all have guids, and they are being used instead of hashstrings. Does it matter if I don't create a guid for my buffs? And how can I create a guid for the buffs?

Also, thanks very much, peter, for the unprotect program, it works like charm. (edit for nvm)

My Mod Index | My Mods at Simlogical | My Blog: Nona's Sims | Fix Your Premium Content

Please do not PM me with questions about modding. Please post in an appropriate forum and PM me a link to the thread if you would like me to try and help.
Top Secret Researcher
#18 Old 3rd May 2012 at 8:10 PM
Quote:
Originally Posted by Consort
You're saying you are intentionally hiding the OnWorldLoadFinishedEventHandler with your script and it's fine to use sOnWorldLoadFinishedEventHandler instead?


Sorry, did not notice your post until now.

Yes, using sOnWorldLoadFinishedEventHandler directly would be an appropriate solution, or simply change the permissions on the delegate function back to public.


NRaas Industries: Sims 3 Mods for the Discerning Player, hosted by The Wikispaces.
1978 gallons of pancake batter
#19 Old 5th May 2012 at 2:39 PM
nonamena, it's probably easiest if you just take a look at my Roundhouse mod. It's small and simple and comes with a custom buff, so it should be a perfect reference.

The code to load the buff is just this:
Code:
private void LoadBuffData()
{
    this.AddBuffs(null);
    Sims3.UI.UIManager.NewHotInstallStoreBuffData += new Sims3.UI.UIManager.NewHotInstallStoreBuffCallback(this.AddBuffs);
}
private void AddBuffs(ResourceKey[] resourceKeys)
{
    ResourceKey key = new ResourceKey(ResourceUtils.HashString64("TwoBTech_ChuckNorris_Buffs"), 0x0333406C, 0x0);
    XmlDbData data = XmlDbData.ReadData(key, false);
    if (data != null)
    {
        BuffManager.ParseBuffData(data, true);
    }
}

If you look at the BuffChuckNorris class, you'll see that it's basically empty. The StaticGuid property is how I address the buff inside the code. The related ulong value is the one that is in the TwoBTech_ChuckNorris_Buffs XML resource in the Hex node.

HTH

If gotcha is all you’ve got, then you’ve got nothing. - Paul Krugman
Forum Resident
#20 Old 7th May 2012 at 12:23 PM
Buzzler, thanks very much for answering. This has helped a lot! I really appreciate it. I'm still unsure about how you converted BuffChuckNorris=0xEA82B27204EF370B into a ulong? Did you use GetGuid from the BuffManager? I have no idea how to do this and I think, maybe, this might be why my buffs are not actually being loaded into the game.

My Mod Index | My Mods at Simlogical | My Blog: Nona's Sims | Fix Your Premium Content

Please do not PM me with questions about modding. Please post in an appropriate forum and PM me a link to the thread if you would like me to try and help.
1978 gallons of pancake batter
#21 Old 7th May 2012 at 1:29 PM
I'm not quite sure what you mean. The value isn't calculated at runtime or anything. It's in the XML like that and in the code like this
private const ulong kChuckNorrisGuid = 0xEA82B27204EF370BL;

The actual value doesn't matter at all. It just has to be the same in both cases. I've used the FNV64 hash of "BuffChuckNorris", though.

If gotcha is all you’ve got, then you’ve got nothing. - Paul Krugman
Forum Resident
#22 Old 7th May 2012 at 2:36 PM
Haha. I see. When I de-compile your script with ILSpy it looks like this:
private const ulong kChuckNorrisGuid = 16898264954626324235uL;

But I knew that 0xEA82B27204EF370BL was the FNV64 hash of BuffChuckNorris, so as you might imagine, I was completely and utterly stupidly confused. But now I know! And I feel a little silly.

But my moodlets still won't load So if you have a spare moment at some point and you're feeling bored, perhaps you could take a look (if you don't have time or the inclination to look, I understand). The script for the object is working: the sim can eat an object that uses my script class, and the sims's hunger motive will increase. But no custom moodlets are being applies (or loaded). I think I know why but I don't know how to fix it.

Right now, only BuffTastyTreat is "ready" for testing, which I'm trying to apply when a sim eats a NonaDriedFoodLow object. I don't have the images or anything for the other two, and the STBLs aren't done.
Download - please read all instructions before downloading any files!
File Type: zip NonaEdibleFood-TESTBuffs.zip (12.4 KB, 18 downloads) - View custom content
Description: mod package
File Type: zip VS2010_Project_NonaEdibleFood.zip (44.2 KB, 17 downloads) - View custom content
Description: non-functioning vs2010 project

My Mod Index | My Mods at Simlogical | My Blog: Nona's Sims | Fix Your Premium Content

Please do not PM me with questions about modding. Please post in an appropriate forum and PM me a link to the thread if you would like me to try and help.
1978 gallons of pancake batter
#23 Old 7th May 2012 at 5:49 PM
Shoot, I thought that would be obvious... noticed the IWantToKnowStuff thing in my BuffBooter declaration and the Subscribe() method? That's for my class loader (not sure if I should dare to call it framework *g*). After startup it searches for all classes that implement that interface, instantiates them and calls the Subscribe() method and passes itself as parameter. That way I don't have to do everything manually and have looser coupling.


Anyway, try to put this into the static constructor of your Instantiator class:
Code:
LoadSaveManager.ObjectGroupsPreLoad += OnPreLoad;

(Hint: That will only work if you altered the libraries to make that event accessible. IIRC anyway.)

plus this callback method:
Code:
private static void OnPreLoad()
{
    (new BuffBooter()).LoadBuffData();
}
Disclaimer: The above code is written manually into the reply and untested.

Long story short: your BuffBooter class never gets instantiated and the LoadBuffData() method never called right now.

If gotcha is all you’ve got, then you’ve got nothing. - Paul Krugman
Forum Resident
#24 Old 8th May 2012 at 1:49 PM Last edited by nonamena : 10th May 2012 at 11:21 AM.
Quote:
Originally Posted by Buzzler
Long story short: your BuffBooter class never gets instantiated and the LoadBuffData() method never called right now.

Thanks again, Buzzler. I had a feeling that was the problem, but I wasn't sure how to fix it.

I tried for the rest of the day yesterday to make the script work, using your advice and whatever variations I could think of. I can compile the script (so my libraries are ok. I used peter's unprotect program and have completely removed all references and then re-added them several times to be sure) I still can't get my custom buffs loaded into the game. I'd really love to get this working, but I seem to be in over my head (typical for me).

If you have another moment when you're bored and have nothing better to do, I'd greatly value your insight. Thanks again for all your help with this already.

Edit: We solved it. The problem was my Buffs XML.
Download - please read all instructions before downloading any files!
File Type: zip NonaEdibleFood-TESTBuffs.zip (24.0 KB, 27 downloads) - View custom content
Description: new package file
File Type: zip NonaEdibleFood2010.zip (43.6 KB, 24 downloads) - View custom content
Description: new vs 2010 project

My Mod Index | My Mods at Simlogical | My Blog: Nona's Sims | Fix Your Premium Content

Please do not PM me with questions about modding. Please post in an appropriate forum and PM me a link to the thread if you would like me to try and help.
Theorist
#25 Old 8th Sep 2012 at 11:20 AM
Quote:
Originally Posted by pljones
Here's a little program to make this even easier.

Drop a .Net DLL onto the .exe and it'll disassemble it, unprotect it and reassemble it "in place" (taking a backup).

It has prerequisites of ILDASM and ILASM.

Source included in the .7z for those interested.

Thanks to Twallan for the method of unprotecting.


For some reason, after I did this and reload the dll in Visual C# 2008 Express it doesn't recognize the dll anymore. Any idea what I'm doing wrong?
Screenshots
Page 1 of 2
Back to top