Help with Protection level of Code

Users who are viewing this thread

i was fixing a dead mod (Workshop Stash) and had a problem with this code:

C#:
        protected override void DefineGenericClassDefinitions()

        {

            this.ConstructGenericClassDefinition(typeof(MBObjectManager.ObjectTypeRecord<TownWorkshopStash>));

        }

the problem MBObjectManager.ObjectTypeRecord is inaccessible due to its protection level
what should i do?
 
Last edited:
Solution
I looked how DefineGenericClassDefinitions is used in the current code, and it seems to have changed quite a bit. It appears a new ObjectManager was introduced, the old one has been renamed but is still in use. The line should now look like this, I'm pretty sure:

Code:
base.ConstructGenericClassDefinition(typeof(ObsoleteObjectManager.ObjectTypeRecord<TownWorkshopStash>));

These types are not protected so the AccessMethod or Traverse stuff is not necessary anymore.
Use Harmony. It has AccessTools and Traverse classes to help with this sort of thing. I don't know the exact answers but these lines may be a good start:

C#:
Type IObjectTypeRecord_type = AccessTools.TypeByName("MBObjectManager.IObjectTypeRecord");
var ObjectTypeRecords = Traverse.Create(MBObjectManager.Instance).Field("ObjectTypeRecords").GetValue();

That second line should give you a variable with a List of all ObjectTypeRecords of the MBObjectManager instance.
 
Upvote 0
Use Harmony. It has AccessTools and Traverse classes to help with this sort of thing. I don't know the exact answers but these lines may be a good start:

C#:
Type IObjectTypeRecord_type = AccessTools.TypeByName("MBObjectManager.IObjectTypeRecord");
var ObjectTypeRecords = Traverse.Create(MBObjectManager.Instance).Field("ObjectTypeRecords").GetValue();

That second line should give you a variable with a List of all ObjectTypeRecords of the MBObjectManager instance.

Thx for the tip, but i don't know what to do next i am just a beginner also i still got is inaccessible due to its protection level

C#:
    public class WorkshopStashSaveableTypeDefiner : SaveableTypeDefiner
    {
        public WorkshopStashSaveableTypeDefiner() : base(4005000) { }

        protected override void DefineClassTypes()
        {
            this.AddClassDefinition(typeof(TownWorkshopStash), 1);
        }

        protected override void DefineGenericClassDefinitions()
        {
            Type IObjectTypeRecord_type = AccessTools.TypeByName("MBObjectManager.IObjectTypeRecord");
            var ObjectTypeRecords = Traverse.Create(MBObjectManager.Instance).Field("ObjectTypeRecords").GetValue();

            this.ConstructGenericClassDefinition(typeof(MBObjectManager.ObjectTypeRecord<TownWorkshopStash>));
        }

        protected override void DefineContainerDefinitions()
        {
            this.ConstructContainerDefinition(typeof(List<TownWorkshopStash>));
            this.ConstructContainerDefinition(typeof(Dictionary<MBGUID, TownWorkshopStash>));
            this.ConstructContainerDefinition(typeof(Dictionary<string, TownWorkshopStash>));
        }
    }
 
Last edited:
Upvote 0
Hmm try this then:

C#:
            protected override void DefineGenericClassDefinitions()
            {
                Type IObjectTypeRecord_type = AccessTools.TypeByName("MBObjectManager.ObjectTypeRecord<TownWorkshopStash>");
                this.ConstructGenericClassDefinition(IObjectTypeRecord_type);
            }
 
Upvote 0
I looked how DefineGenericClassDefinitions is used in the current code, and it seems to have changed quite a bit. It appears a new ObjectManager was introduced, the old one has been renamed but is still in use. The line should now look like this, I'm pretty sure:

Code:
base.ConstructGenericClassDefinition(typeof(ObsoleteObjectManager.ObjectTypeRecord<TownWorkshopStash>));

These types are not protected so the AccessMethod or Traverse stuff is not necessary anymore.
 
Upvote 0
Solution
I looked how DefineGenericClassDefinitions is used in the current code, and it seems to have changed quite a bit. It appears a new ObjectManager was introduced, the old one has been renamed but is still in use. The line should now look like this, I'm pretty sure:

Code:
base.ConstructGenericClassDefinition(typeof(ObsoleteObjectManager.ObjectTypeRecord<TownWorkshopStash>));

These types are not protected so the AccessMethod or Traverse stuff is not necessary anymore.

Thx it worked

hehe the mod still has a problem, when loading a game the things in the stash disappear
i think the problem is in other class
 
Upvote 0
I looked how DefineGenericClassDefinitions is used in the current code, and it seems to have changed quite a bit. It appears a new ObjectManager was introduced, the old one has been renamed but is still in use. The line should now look like this, I'm pretty sure:

Code:
base.ConstructGenericClassDefinition(typeof(ObsoleteObjectManager.ObjectTypeRecord<TownWorkshopStash>));

These types are not protected so the AccessMethod or Traverse stuff is not necessary anymore.

this class has a problem (last problem in the mod)

C#:
public class WorkshopStashSubModule : MBSubModuleBase
    {
        protected override void OnGameStart(Game game, IGameStarter gameStarterObject)
        {
            if (!(game.GameType is Campaign))
            {
                return;
            }

            MBObjectManager.Instance.RegisterType<TownWorkshopStash>("TownWorkshopStash", "TownWorkshopStashes");

            if (gameStarterObject is CampaignGameStarter starter)
            {
                starter.AddBehavior(new WorkshopStashCampaignBehavior());
            }

            new HarmonyLib.Harmony("WorkshopStashMod.patcher").PatchAll();
        }
    }

this is the problem MBObjectManager.Instance.RegisterType<TownWorkshopStash>("TownWorkshopStash", "TownWorkshopStashes");

sorry i am asking too much from you
 
Upvote 0
You can try this, but only for personal use! I don't recommend publishing the mod like this even if it works.

C#:
MBObjectManager.Instance.RegisterType<ItemObject>("TownWorkshopStash", "TownWorkshopStashes", 59U);

The number 59U at the end is a TypeID which appears to be the first 6 bits of the 32 bit MBGUID, which is basically the unique ID of every object of the world. It's a bit problematic because with 6 bits we have only the numbers 0 to 63 available. The base game appears to have at least the first 45 values in use. If public mods start using the remaining numbers we're going to have conflicts, and that might cause a lot of trouble. I wouldn't proceed with publishing it like this unless we learn more.

I never registered my saveable classes to the ObjectManager like that and given the limited amount of space of the TypeID that probably shouldn't be used in general, unless there turns out to be a reserved TypeID value for custom classes. What I would do in this case is create a Dictionary<Town, TownWorkshopStash>, register it in the SaveableTypeDefiner subclass and sync the data with the savegame in the Behavior's SyncData method, and then use the Dictionary to look up the stash for a particular town elsewhere in the code.

Maybe there's a better method than that, but it's worked well for me so far.
 
Upvote 0
You can try this, but only for personal use! I don't recommend publishing the mod like this even if it works.

C#:
MBObjectManager.Instance.RegisterType<ItemObject>("TownWorkshopStash", "TownWorkshopStashes", 59U);

The number 59U at the end is a TypeID which appears to be the first 6 bits of the 32 bit MBGUID, which is basically the unique ID of every object of the world. It's a bit problematic because with 6 bits we have only the numbers 0 to 63 available. The base game appears to have at least the first 45 values in use. If public mods start using the remaining numbers we're going to have conflicts, and that might cause a lot of trouble. I wouldn't proceed with publishing it like this unless we learn more.

I never registered my saveable classes to the ObjectManager like that and given the limited amount of space of the TypeID that probably shouldn't be used in general, unless there turns out to be a reserved TypeID value for custom classes. What I would do in this case is create a Dictionary<Town, TownWorkshopStash>, register it in the SaveableTypeDefiner subclass and sync the data with the savegame in the Behavior's SyncData method, and then use the Dictionary to look up the stash for a particular town elsewhere in the code.

Maybe there's a better method than that, but it's worked well for me so far.

thank you for everything , when i find another method which doesn't do anything you said then i will publish the mod

gotta admit i don't know what those cods do yet , i started learning C# 5 day ago , soon i will be able to do like you hehe thx again

i will have the mod updated with every version and publish it when it's safe
 
Upvote 0
Back
Top Bottom