jrossignol / ContractConfigurator

A config file based solution for creating new contracts for Kerbal Space Program.
https://forum.kerbalspaceprogram.com/index.php?/topic/91625-1
Other
64 stars 67 forks source link

support request - how to eliminate random duplicates #365

Closed inigmatus closed 8 years ago

inigmatus commented 8 years ago

Referencing #355 you gave an example of two random Kerbal names. Doing so tends to create duplicate Kerbal names sometimes, which the game eliminates the similarly named Kerbal from the spawned vessel, but the contract still requires that extra Kerbal in the contract to be accounted for, thus hanging the contract.

So... I'm trying to figure out a way to generate two kerbal names that do not match:

DATA
{
    type = string
    kerbal1 = RandomKerbalName(Random())
    kerbal2 = RandomKerbalName(Random()).Where(n != n.@/kerbal1)
}

But this fails. I suspect my syntax is incorrect, or I need to do something different.

I've found that if I just

DATA
{
    type = string
    kerbal1 = RandomKerbalName(Random())
    kerbal2 = RandomKerbalName(Random())
}

There is a probability (actually quite high) that the two kerbal names will be the same. Just trying to eliminate the duplicate possibility.

inigmatus commented 8 years ago

Rather than trying to figure out how to eliminate random duplicates, I figured I'd just do this:

BEHAVIOUR
{
    name = TourBus
    type = SpawnVessel
    deferVesselCreation = false

    VESSEL
    {
        name = Tour Bus
        craftURL = ContractPacks/SSI-Aerospace/Assets/TouristBus.craft
        vesselType = Ship
        owned = True
        targetBody = Kerbin
        lat = -0.0544780548632459
        lon = 285.275492359036

        CREW
        {
            addToRoster = false
            name = RandomKerbalName(Random())
        }

        CREW
        {
            addToRoster = false
            count = 1
        }

    }

}

//this passes into DATA fine (and can be used in HasPassengers fine):
DATA
{
    type = string
    kerbal2 = @/TourBus.Kerbals().ElementAt(0)
}

//this fails with errors and is not passed into DATA (and thus can not be used in HasPassengers):
DATA
{
    type = string
    kerbal2 = @/TourBus.Kerbals().ElementAt(1)
}

Thoughts?

jrossignol commented 8 years ago

The correct syntax would be:

DATA
{
    type = string
    kerbal1 = RandomKerbalName(Random())
    kerbal2 = RandomKerbalName(Random()).Where(k => k != @/kerbal1)
}

However, this shouldn't be necessary, looks like a stock bug/limitation. Because it create a new random number generator each time, it uses the same seed until the clock ticks over. I can just pass my own generator in, and it should reduce the collision chance to basically nothing.

jrossignol commented 8 years ago

Fixed for 1.8.4

inigmatus commented 8 years ago

Thanks, you sir are awesome!

inigmatus commented 8 years ago

Any reason why

    CREW
    {
        addToRoster = false
        name = RandomKerbalName(Random())
    }

    CREW
    {
        addToRoster = false
        count = 1
    }

//this passes into DATA fine (and can be used in HasPassengers fine): DATA { type = string kerbal2 = @/TourBus.Kerbals().ElementAt(0) }

//this fails with errors and is not passed into DATA (and thus can not be used in HasPassengers): DATA { type = string kerbal2 = @/TourBus.Kerbals().ElementAt(1) }

any reason why the second example Crew node is not passing the kerbal name to the DATA node?

jrossignol commented 8 years ago

Please provide the errors it failed with, that's critical information to diagnose this type of issue.

inigmatus commented 8 years ago

I hate piggy backing side trains with main issues. I can't wait until the forums are back up. But to answer your question, yes there are errors. See below.

Both DATA notes below (using latest dev build of CC as of this writing) fail to load in the corresponding CREW node kerbal name whenever a CREW node uses the count attribute. Neither can HasPassengers find anything in Kerbals() and thus fails to list names.

BEHAVIOUR
{
    name = TourBus
    type = SpawnVessel
    deferVesselCreation = false

    VESSEL
    {
        name = Tour Bus
        craftURL = ContractPacks/SSI-Aerospace/Assets/TouristBus.craft
        vesselType = Ship
        owned = True
        targetBody = Kerbin
        lat = -0.0544780548632459
        lon = 285.275492359036

        CREW
        {
            addToRoster = false
            name = RandomKerbalName(Random())
        }

        CREW
        {
            addToRoster = false
            count = 1
        }

    }

}

DATA
{
    type = string
    kerbal1 = @/TourBus.Kerbals().ElementAt(0)
    kerbal2 = @/TourBus.Kerbals().ElementAt(1)
}

PARAMETER
{
    name = HasPassengers
    type = HasPassengers

    name = @/TourBus.Kerbals().ElementAt(0)
    name = @/TourBus.Kerbals().ElementAt(1)

    disableOnStateChange = false
}

errors are:

[Error]: ContractConfigurator.ContractType: CONTRACT_TYPE 'BugTest': Error parsing kerbal1 [Exception]: NotSupportedException: Unsupported type: ContractConfigurator.Behaviour.SpawnVesselFactory

[Error]: ContractConfigurator.ContractType: CONTRACT_TYPE 'BugTest': Error parsing kerbal2 [Exception]: NotSupportedException: Unsupported type: ContractConfigurator.Behaviour.SpawnVesselFactory

The above DATA node is really meant to capture the names of the Kerbals spawed by SpawnVessel/Crew for use in other places, such as use in HasPassengers.

Now when I switch all CREW nodes to use RandomKerbalName shown below, instead of the count attribute above, the DATA node still can't seem to load the names into kerbal1 and kerbal2 (log spits out same exact errors above); but... HasPassengers can seemingly use Kerbal() to pull out the names for use in HasPassengers. HasPassengers seems to work fine in this scenario so kludging together a work around is possible at this point. It remains messy though, since I will have to do your gender array suggestion that you shared in #355 to keep gender matching when using RandomKerbalName as a source for CREW node kerbal generation, and later reference by HasPassengers:

BEHAVIOUR
{
    name = TourBus
    type = SpawnVessel
    deferVesselCreation = false

    VESSEL
    {
        name = Tour Bus
        craftURL = ContractPacks/SSI-Aerospace/Assets/TouristBus.craft
        vesselType = Ship
        owned = True
        targetBody = Kerbin
        lat = -0.0544780548632459
        lon = 285.275492359036

        CREW
        {
            addToRoster = false
            name = RandomKerbalName(Random())
        }

        CREW
        {
            addToRoster = false
            name = RandomKerbalName(Random())
        }

    }

}

DATA
{
    type = string
    kerbal1 = @/TourBus.Kerbals().ElementAt(0)
    kerbal2 = @/TourBus.Kerbals().ElementAt(1)
}

PARAMETER
{
    name = HasPassengers
    type = HasPassengers

    name = @/TourBus.Kerbals().ElementAt(0)
    name = @/TourBus.Kerbals().ElementAt(1)

    disableOnStateChange = false
}

So yes, I get the same errors as above for the DATA node's variables kerbal1 and kerbal2, but this time HasPassengers is able to read names and list them in the contract parameters window.

The idea I was shooting for was hoping that DATA and HasPassengers could use a syntax like @/TourBus.Kerbals().ElementAt(0) to reference crew spawned via SpawnVessel/Crew's count attribute. If so, I would not have to worry about gender matching since the Crew count attribute (I assume) does this already. All I would have to do is simply set Crew to count the number of Kerbals I want, and then reference the correct elements in Vessel.Kerbals() in HasPassengers to get those crew members to show up on the contract parameter list as a required passenger to pick up.

Btw, thank you so much for answering all my questions. I was wondering if you'd like my Island Tour to Valentina's Cay be renamed after you. You sir, are amazing.

jrossignol commented 8 years ago

I hate piggy backing side trains with main issues. I can't wait until the forums are back up. But to answer your question, yes there are errors. See below.

Agreed, so let's move this to a new (and not closed issue). Raised #366