Copying a class versus retaining a reference to that class

My skill system requires a little bit of manual configuration to build the skill trees in the inspector, so I want to drag a single SkillSystem.cs onto some empty SkillLogic gameobject, spend hours carefully dragging and dropping skills, setting training requirements, and so forth. When the game actually runs, I want to give every NPC their own version of the specific SkillSystem.cs I already configured in SkillLogic, so everybody has access to the same skills, and the same requirements to train. However, what I don’t want is to give everyone a reference to a single SkillSystem.cs, leading to everyone sharing a single skill tree. To that end, I’m wondering if someone could help clarify the difference between creating a reference to a script versus a copy of that script? I’m under the impression that if I say

SkillSystem bob = new SkillSystem();

SkillSystem dan = bob;

I will have created a single SkillSystem (bob), and told dan to point at bob and update based on changes to bob. Is there specific syntax to specify that I want dan to be a second SkillSystem which starts as a copy of bob, but never consults him again once all values have been set?

No, in that example you’re making a single SkillSystem and are referring to it as both “bob” and “dan”. dan isn’t being updated based on changes to bob, dan is bob. They are the same thing. They both point to the same physical data in your computer’s memory.

Out of interest, why do you not want them to all use the same skill tree? Does it get modified per-character at some point, or…?

Well my skill system is designed to be extremely modular, to the point that a little manual configuration is required. Each skill is a subclass that extends Skill.cs and uses overrides to apply whatever passive or active effects are unique to that skill, and my SkillTree class is just a single list. Each Skill has a variable of type list, and TrainingRequirement is just a data holder class that has two variables: Skill skill and float level. Whenever the skill tree is modified, the game quickly iterates through each skill where skill.Trainable=false, iterates through that skill’s list to check if the player or NPC has every TrainingRequirement.skill at level TrainingRequirement.level, and if they do, that skill’s skill.Trainable is set to true, allowing the player/NPC to invest points in it.

This is simple and hard to break, but the big downside is that at some point I need to go through and manually set each skill’s training requirements through the inspector by, for example, setting the Arithmetic skill’s list to length 2, dragging the Reading and Writing skill from the same tree into the two TrainingRequirement.skill slots, then manually setting the TrainingRequirement.level on each to 1, or 3, or whatever value I want.

My thinking is to assemble the tree once, maintain that as the master version of what the game’s skill tree looks like, then copy it to the player and NPCs at chargen to ensure that everyone is working from the same document.

I’d definitely love feedback if this is a fundamentally silly way to do things, though- it seemed extremely simple when I implemented it, but in reading my own description of it here it sounds like a really terribly grindy way to go about things.

Once it’s set up, is the skill tree the same tree for every character that uses it? Or does each character have a different version?

It’s the exact same tree for every character that uses it, the version I’m talking about manually building in the inspector is basically a template for what everybody in the world who requests a skill tree from the game’s logic gets.

Do characters modify their copy of the skill tree?

Yep, every character builds their own tree, so ultimately I’d be looking at 500-600 versions of the same tree with different skills taken.

So it occurs to me that I could make a single SkillMaster class, and instead of dragging and dropping in the inspector, simply configure everything in the constructor, but that doesn’t seem like a particularly clean way to do things either- is there an obvious, better way to preconfigure the tree than what I’ve proposed doing?