Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

@Dmagic: I'm actually using that for a custom identifier character in saving, one quirk I ran into was that " (double quotes) don't work, you have to use ' (single quotes).

DisplayString = DegreesInInt.ToString("00") + "\u0176";

throws an error while

DisplayString = DegreesInInt.ToString("00") + '\u0176';

works.

If the second method still does not work, the next place I would look is at whichever GUI.style the right click menu uses to figure what it is doing with fonts.

@Faark: I'm currently storing configured action groups as a single string, but I'm doing it on a per part basis, not a per vessel basis. That way docking two ships together does not wipe out the action groups on the child vessel. I'm using a persistent KSPField(string) to store this data.

My issue is that I don't keep that string up to date in realtime. So when I save, I have to take my list of configured action groups, save only the actions that apply to that part, make my string to save for that part and write the string......

...

/headdesk, repeatedly.

The string is different for each part, why I am worried about this? Moving my save methods to the PartModule's OnSave.

On the multi-thread thing, I think we are talking past each other.

I was thinking of trying something like this.

In editor, ListAG as List<ActionGroups>, SavePartGroups(p)

SavePartGroups being the save method that returns a string with the configured actions for that part and a 3 second time delay check so it never runs more often then 3 seconds.

Then in each partmodule OnSave() event, call SavePartGroups(this part)

My worry was that if the partmodules all called OnSave at the same time, it would bypass the 3 second time check and rather then running the calculations to make the code once and coping the string out to each part, it would run the calculations for each part and then copy each generated string to a single part. This is not multi-threading in the typical sense of the word (I don't think).

As it is, I'd overlooked the fact that the calculation has to be run for each part anyway as the save string will be different, so I'll just move the call to save to the partmodule's OnSave event and bypass this entire mess.

On my code, I do have to warn you I come into this with limited programming experience in VB and while I wave in the general direction of best-practice, I know my code is a mess. I am going to post my thought process and stuff in my mod's development thread when I am ready to release so hopefully there will be something of interest there.

D.

edit: Doing that however does raise a couple issues I need to work around with docked vessel's. So, two questions.

1) When two vessel's dock, is there an identifier of some sort that I can reference to tell which parts belong to which vessel? IE: I launch "Lifter1" with FlightID10 and "Lander1" with FlightID11. I dock the two and now have a single vessel "Lifter1", but do any of the parts from FlightID11 save anything I can use to tell them apart from FlightID10?

2) What happens to root parts when you dock? From my previous example, once docked, the root part for "Lander1/FlightID11" is now the same root part as for "Lifter1/FlightID10" correct?

D.

Edited by Diazo
Link to comment
Share on other sites

My worry was that if the partmodules all called OnSave at the same time, it would bypass the 3 second time check and rather then running the calculations to make the code once and coping the string out to each part, it would run the calculations for each part and then copy each generated string to a single part.

Parts are saved sequentionally, one after the other. There's no case in which multiple OnSaves will run simultaneously, in parallel

Link to comment
Share on other sites

ScenarioModule? No, I did not even consider that.

Mostly because I don't even know what one is really, beyond the fact that it sets up the tutorial stuff you can select from the main menu.

I'm going to read up on them a bit now that you have piqued my interest on them, but I don't see myself changing my data saving strategy this close to getting my mod ready to go.

D.

Link to comment
Share on other sites

Ya, I just took a quick look at Harvester's blog where he talks about them.

Most of my data is saved on a per part basis, with a little bit saved on a per vessel basis to handle docking and stuff.

I'm not actually saving anything on a scene or game wide basis for my current mod.

Having said that, ScenarioModule looks to be a very powerful tool for a future mod of mine that I'm turning over in the back of my head.

Anyways, my original question about saving has been answered, I'll be moving my save method to the partmodule's OnSave and just bypass my original problem of the editor scene not having an OnSave event.

D.

Edited by Diazo
Link to comment
Share on other sites

@Dmagic: I'm actually using that for a custom identifier character in saving, one quirk I ran into was that " (double quotes) don't work, you have to use ' (single quotes).

DisplayString = DegreesInInt.ToString("00") + "\u0176";

throws an error while

DisplayString = DegreesInInt.ToString("00") + '\u0176';

works.

If the second method still does not work, the next place I would look is at whichever GUI.style the right click menu uses to figure what it is doing with fonts.

The single quotes, I believe, are used for single characters, while the doubles are for strings, so I guess it only considers the unicode key as a character.

I tried that method, and a few others for trying to insert the symbol as a character, but none worked in the right-click menu. After looking at Squad's parts I realized none of them have special characters in that menu either, so I'm guessing they're using some font or style that doesn't allow it. I guess I can just use "Deg" for now as I'm really using the right-click menu as a place-holder for now.

Link to comment
Share on other sites

Anyone who saw the previous version of this post, please ignore my late night rants about things not working.

A more concise summary of the issue I'm running into follows.

I am working in the editor, trying to save a string to a KSPField Persistent string in the .craft file.

 [KSPField(isPersistant = true, guiActive = false)]
public string AGXData;

The following works:

In Partmodule OnSave()
{
AGXData = "test";
print(AGXData);
}

This saves 'test' to the .craft file and prints 'test' to the console as expected.

However, as soon as I try to calculate the string, this breaks. While the string is always printed to the console correctly, it does not save to the craft file.

Partmodule:

OnSave()
{
AGXData = "Test1" + "test2";
print(AGXData);
}

This prints the string to the console correctly (Test1test2 in this case), but the .craft file has nothing, AGXData = *empty string with no characters*.

I've tried messing around with .ToString() thinking it maybe was a formatting issue, so

string Temp = "Test1" + "test2";
AGXData = Temp.ToString();
print(AGXData);

also prints to console while saving nothing.

I am now at a total loss, why do some strings save and some not?

The only difference I can think of is that stuff I type in quotes, so "test", works while stuff I calculate like so: SaveString = "test1" + "test2"; does not.

Help?

D.

Edited by Diazo
Link to comment
Share on other sites

I am working in the editor, trying to save a string to a KSPField Persistent string in the .craft file.

That's weird, I just tried this with something I'm working on and it seems to work fine.


[KSPField(isPersistant = true)] //guiActive = false, guiName = "Bt"
public string Bt;

//Running in OnUpdate()

double uTime = Planetarium.GetUniversalTime();
Bt = uTime.ToString();

I tried this with and without the guiActive and guiName fields included and it worked fine with both. Under my part in the persistent file it included: Bt = 44093.4754801721

I don't see why starting with a double and converting it to a string would produce different results from starting directly with a string. I also tried adding + " seconds" to the end of the line and it also works.

Edit: Ignore all that, I see you're talking about the .craft file, not the persistent file.

Edited by DMagic
Link to comment
Share on other sites

It seems like persistence files and craft files partially use the same code for saving. And it seems like PartModule.OnSave(CfgNode) is called after all Fields are already written. The easiest workaround might be to write your data to the given ConfigNode directly...

Link to comment
Share on other sites

I've not looked at accessing the confignode directly before, any hints?

I expect it is pretty easy but I have no access to my dev computer try things out until tomorrow (Saturday).

The other option I've found is in looking at ProceduralParts, specifically the serialized TankTypeOption class at line 129.

That implements a class with the IConfig interface which looks to do what I want.

I'll see what I can get working.

D.

Link to comment
Share on other sites

And in testing, it looks like writing to the config node directly works.

In PartModule OnSave()
{
node.SetValue("AGXData", AGXEditor.SaveActionGroups(this.part));
}

correctly saves my calculation (as string returned by SaveActionGroups()).

So, I can work with this.

D.

Link to comment
Share on other sites

And my next issue.

Does anyone have any idea what might cause this? (From the ksp.o

NullReferenceException
at (wrapper managed-to-native) UnityEngine.Component:InternalGetTransform ()

at UnityEngine.Component.get_transform () [0x00000] in <filename unknown>:0

at SpaceCenterCamera2.UpdateTransformOverview () [0x00000] in <filename unknown>:0

at SpaceCenterCamera2.UpdateTransform () [0x00000] in <filename unknown>:0

at SpaceCenterCamera2.Update () [0x00000] in <filename unknown>:0

My own code is not touching the SpaceCenterCamera in any way, but this sometimes appears when the flight scene initializes and it prevents my ship from spawning.

Any one seen anything like this before?

D.

edit the first: Apparently it was something to do with my code in the OnSave node of my part module calling a method in my Flight Scene code. No clue why it would do that, I was only dealing with my own code objects and nothing from KSP's default objects (I think). Anyways, work-around time.

Edited by Diazo
Link to comment
Share on other sites

Well, something I was doing was triggering it at least.

After trying to add my save method code to the partmodule's onsave, I got this error 9 out of 10 times I switched to the launchpad.

Take the code out, I have not seen it since.

My best guess is that because I know my code had both ArrayOutOfRange and NullRef errors in it, one of those cascaded somehow and when the SpaceCamera loaded KSP was already borked.

Having said that, I have no explanation for why the SpaceCenter camara was the first error logged and as I've implemented another method for saving, I'm not going to experiment to find out.

D.

Link to comment
Share on other sites

In the case of a PartModule class how does one differentiate between the specific part's localPosition and the vessel's root part localPosition?

I have a new PartModule I'm attempting to get working, and I keep returning 0,0,0 as the localPosition of the part no mater where it is in the vessel.

Link to comment
Share on other sites

In the case of a PartModule class how does one differentiate between the specific part's localPosition and the vessel's root part localPosition?

I have a new PartModule I'm attempting to get working, and I keep returning 0,0,0 as the localPosition of the part no mater where it is in the vessel.

Using transform.InverseTransformPoint("root transform position") should give you the root part's position relative to your part's position. I imagine you can flip that around to get your part's position relative to the root part's. There might also be some more direct way of doing it, I've never had to find the reverse like that.

Link to comment
Share on other sites

Alright so this is what I'm trying to work with. The red text is where I've been screwing around. All I ever seem to get is the position and roation of the root part. Can someone explain why I can't seem to access anything about the part accessing the PartModule?

public class sfrInternal : PartModule
{

private Transform kspParent;
private Vector3 kspPosition;
private Quaternion kspRotation;
private bool isActive;
private bool packed;

public override void OnAwake()
{
base.OnAwake();
}

public override void OnLoad(ConfigNode node)
{
base.OnLoad(node);
}

public override void OnSave(ConfigNode node)
{
base.OnSave(node);
}

public override void OnStart(PartModule.StartState state)
{
base.OnStart(state);
}

public override void OnUpdate()
{
base.OnUpdate();

if (!part.internalModel)
{
part.CreateInternalModel();
part.vessel.SetActiveInternalPart(part);
kspParent = part.transform;//InternalCamera.Instance.transform.parent;
if (!part.internalModel)
part.internalModel.SetVisible(true);
part.internalModel.transform.parent = part.transform;
part.internalModel.transform.localRotation = new Quaternion(0.0f, 0.7f, -0.7f, 0.0f);
part.internalModel.transform.localPosition = Vector3.zero;
if (part.protoModuleCrew.Count > 0)
{
part.internalModel.Initialize(part);
part.internalModel.enabled = true;
using (List<ProtoCrewMember>.Enumerator enumerator = ((List<ProtoCrewMember>)part.protoModuleCrew).GetEnumerator())
{
while (enumerator.MoveNext())
{
ProtoCrewMember current = enumerator.Current;
if (current.seat && !part.vessel.packed)
{
current.seat.enabled = true;
current.seat.SpawnCrew();
}
if (current.KerbalRef)
{
current.KerbalRef.enabled = true;
current.KerbalRef.kerbalCam.cullingMask = 1;
}
}
}
using (List<InternalSeat>.Enumerator enumerator = part.internalModel.seats.GetEnumerator())
{
while (enumerator.MoveNext())
{
InternalSeat current = enumerator.Current;
if (current.kerbalRef)
current.SpawnCrew();
if (current.portraitCamera != null)
current.portraitCamera.cullingMask = 65537;
}
}
}
}
Exception exception;
if (isActive != part.vessel.isActiveVessel && !vessel.packed)
{
isActive = part.vessel.isActiveVessel;
if (part.internalModel && part.protoModuleCrew.Count > 0)
{
part.vessel.SetActiveInternalPart(part);
part.internalModel.Initialize(part);
using (List<InternalSeat>.Enumerator enumerator = part.internalModel.seats.GetEnumerator())
{
while (enumerator.MoveNext())
{
InternalSeat current = enumerator.Current;
current.enabled = true;
if (current.portraitCamera)
current.portraitCamera.cullingMask = 1;
}
}
try
{
using (List<ProtoCrewMember>.Enumerator enumerator = part.protoModuleCrew.GetEnumerator())
{
while (enumerator.MoveNext())
{
ProtoCrewMember current = enumerator.Current;
if (current.seat && !part.vessel.packed)
{
current.seat.enabled = true;
current.seat.SpawnCrew();
}
if (current.KerbalRef)
{
current.KerbalRef.enabled = true;
current.KerbalRef.kerbalCam.cullingMask = 1;
}
}
}
}
catch (Exception ex)
{
exception = ex;
}
}
}
try
{
if (sfrUtility.FindCamera("InternalCamera") && part.vessel.isActiveVessel)
{
[COLOR="#FF0000"] sfrUtility.ChangeLayer(part.internalModel.transform, 16);
part.internalModel.transform.parent = kspParent; // = InternalCamera.Instance.transform.parent;
part.internalModel.transform.localRotation = new Quaternion(0.0f, 0.7f, -0.7f, 0.0f); //Working at root
part.internalModel.transform.localPosition = Vector3.zero; //Working at root[/COLOR]
}
else
{
sfrUtility.ChangeLayer(part.internalModel.transform, 0);
part.internalModel.SetVisible(true);
part.internalModel.gameObject.SetActive(true);
part.internalModel.transform.parent = part.transform;
part.internalModel.transform.localRotation = new Quaternion(0.0f, 0.7f, -0.7f, 0.0f);
part.internalModel.transform.localPosition = Vector3.zero;
}
}
catch (Exception ex)
{
exception = ex;
}
try
{
using (List<ProtoCrewMember>.Enumerator enumerator = part.protoModuleCrew.GetEnumerator())
{
while (enumerator.MoveNext())
{
ProtoCrewMember current = enumerator.Current;
if (current.seat)
{
current.seat.enabled = true;
if (current.seat.portraitCamera)
current.seat.portraitCamera.cullingMask = (65537);
}
if (current.KerbalRef)
{
current.KerbalRef.enabled = true;
current.KerbalRef.kerbalCam.cullingMask = (65537);
if (current.KerbalRef.kerbalCamOverlay)
current.KerbalRef.kerbalCamOverlay.layer = 16;
}
}
}
}
catch (Exception ex)
{
exception = ex;
}
}
}

}

Edited by Alskari
Link to comment
Share on other sites

Alright so this is what I'm trying to work with. The red text is where I've been screwing around. All I ever seem to get is the position and roation of the root part. Can someone explain why I can't seem to access anything about the part accessing the PartModule?

Do you want it in world or local coordinates? And if from local coordinates, by setting the origin where? Getting world coordinates for the part accessing the PartModule is as easy as "Vector3 pos = this.part.transform.location;". If you want it in local coordinates from the root part, it would simply be something like "Vector3 localPos = this.vessel.rootPart.tranform.location - this.part.transform.location;" You can apply the same logic to anything you would want.

Link to comment
Share on other sites

How can i add some option to right click menu when i click on kerbal on EVA?

I mean option not associated with any part, like plant flag or eva report.

Kerbals are essentially one part vessels with a KerbalEVA PartModule. You can simply create a partmodule that does what you want, and then add that module to all EVA'ed Kerbals.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...