Jump to content

[1.12.x] kRPC: Control the game using C#, C++, Java, Lua, Python, Ruby, Haskell, C (Arduino)... (v0.5.4)


djungelorm

Recommended Posts

Typically what I do in the case of hard dependencies is separate out the functionality that needs that other mod, and place it into a separate DLL.  If setup properly KSP will then only load that DLL if the other mod is present, or ignore it if not.

For example this is how TestFlight hooks into RealFuels without actually requiring RealFuels.  Same with TestFlight and ContractConfigurator.

Link to comment
Share on other sites

I don't think that approach works here though? To add RPCs you annotate bits of your mod with the kRPC attributes - but moving this functionality to another DLL could result in moving your entire mod to another DLL which kinda defeats the point. For example, if MechJeb wanted to make its functionality available as RPCs, you could annotate the relevant classes with the [KRPCMethod] etc. attributes in the relevant places. But separating this functionality out into a separate DLL would remove all of MechJebs functionality into a DLL that is only loaded if kRPC is present.

The previous discussion I mentioned was on github here: https://github.com/krpc/krpc/issues/143

Link to comment
Share on other sites

2 minutes ago, Agathorn said:

Typically what I do in the case of hard dependencies is separate out the functionality that needs that other mod, and place it into a separate DLL.  If setup properly KSP will then only load that DLL if the other mod is present, or ignore it if not.

For example this is how TestFlight hooks into RealFuels without actually requiring RealFuels.  Same with TestFlight and ContractConfigurator.

That was what I ultimately resorted to as well, but kOS ended up adding a feature set that meant there was no reason to run my mod without KRPC so I went back to a single implementation.

11 minutes ago, djungelorm said:

Cool idea :) Not sure I quite understand your design but will go have a read on the thread.

The issue of optionally using kRPC actually came up over a year ago, when someone was concerned about having to create a hard dependency against the DLL from any third-party mod that wants to add RPCs. Unfortunately I put this feature request on the back burner and never got around to it! It should be pretty easy to add an API to register RPCs - I think it's just a case of opening up some of the "service scanner" internals.

For your other two concerns, the relevant APIs exist but are indeed private. I can put together a dev build with the those APIs made public so you can play around if you like?

The design notes are actually way out of date.  I've opted to just use JSON as a serialization mechanism and a normal message queue to more or less mirror kOS's new (not yet released) communications mechanism.

Re: a dev build: It'd be nice to add to a future release, but don't fret making a build just for me: If I really want to do it I can always (temporarily) abuse reflection, and I don't want to end up in a situation where people need dev builds of other mods to try the (eventual) dev build of mine :wink:

Oh, the other question I should have asked is: Is there a good mechanism to send arbitrary mixed-type data via KRPC?  Right now I've resorted to JSON (much easier to use than my former idea of getArgumentTypes -> getIntArg, GetStringArg, etc.) or BSON if I can figure out how to make JsonFx do that correctly, but keeping things closer to native types for efficiency is always nice.

 

Link to comment
Share on other sites

In the MechJeb example, MJ exposes an API then moves the kRPC functionality into a separate DLL that uses its own API.  I plan to eventually add a kRPC service for TestFlight and this is exactly what I plan to do.

Not saying it is necessarily ideal, just that it is doable :)

Link to comment
Share on other sites

3 minutes ago, djungelorm said:

I don't think that approach works here though? To add RPCs you annotate bits of your mod with the kRPC attributes - but moving this functionality to another DLL could result in moving your entire mod to another DLL which kinda defeats the point. For example, if MechJeb wanted to make its functionality available as RPCs, you could annotate the relevant classes with the [KRPCMethod] etc. attributes in the relevant places. But separating this functionality out into a separate DLL would remove all of MechJebs functionality into a DLL that is only loaded if kRPC is present.

The previous discussion I mentioned was on github here: https://github.com/krpc/krpc/issues/143

I think he means something like: Mechjeb.dll would have Mechjeb as it is now, and Mechjeb-KRPC.dll would depend on both mods and would have annotated stubs that call the actual Mechjeb functions.

I was originally doing that with KIPCPlugin and KIPCPlugin-KRPC.

Link to comment
Share on other sites

3 minutes ago, dewin said:

I think he means something like: Mechjeb.dll would have Mechjeb as it is now, and Mechjeb-KRPC.dll would depend on both mods and would have annotated stubs that call the actual Mechjeb functions.

I was originally doing that with KIPCPlugin and KIPCPlugin-KRPC.

Yes, exactly.

Link to comment
Share on other sites

Just now, dewin said:

I think he means something like: Mechjeb.dll would have Mechjeb as it is now, and Mechjeb-KRPC.dll would depend on both mods and would have annotated stubs that call the actual Mechjeb functions.

I was originally doing that with KIPCPlugin and KIPCPlugin-KRPC.

Ahhhhhhh I see. Yes that makes sense.

5 minutes ago, dewin said:

Oh, the other question I should have asked is: Is there a good mechanism to send arbitrary mixed-type data via KRPC?  Right now I've resorted to JSON (much easier to use than my former idea of getArgumentTypes -> getIntArg, GetStringArg, etc.) or BSON if I can figure out how to make JsonFx do that correctly, but keeping things closer to native types for efficiency is always nice.
 

Not sure I 100% understand your question, but kRPC uses protocol buffers to serialize data to and from it's client languages. If you want to pass arbitrary data from kOS through to a client script with minimal serialization cost then you should byte[]. But the client would then need to do some work to figure out how to interpret the bytes.

Link to comment
Share on other sites

2 minutes ago, djungelorm said:

Ahhhhhhh I see. Yes that makes sense.

Not sure I 100% understand your question, but kRPC uses protocol buffers to serialize data to and from it's client languages. If you want to pass arbitrary data from kOS through to a client script with minimal serialization cost then you should byte[]. But the client would then need to do some work to figure out how to interpret the bytes.

I knew about the protocol buffers bit, and the big thing was that the structure of the data isn't necessarily known ahead of time.  I think JSON shall suffice for now though.

Link to comment
Share on other sites

Hi  @djungelorm

I will apologise in advance, because I have a few issues now that I am debugging my controller code and I am sure at least some of them will be dumb errors on my part!

1. Camera distance doesn't seem to take effect for about 2 seconds after a camera mode change. I am setting the camera mode (which changes in the game immediately) and then setting camera.distance = camera.default_distance, this wasn't having any effect. So I forced this to set repeatedly and found that despite setting the distance each time on the next run through the code the distance was the original, and only after about 2s it changed. Is there some limitation here with the camera? I can reproduce it with the following snippet (and the cam starting off default zoom) where the last line does nothing, but change the previous sleep to 3s or higher and it works!

import krpc
import time

conn = krpc.connect(name='Game Controller')
vessel = conn.space_center.active_vessel
cam = conn.space_center.camera
time.sleep(2)
cam.mode = cam.mode.locked
time.sleep(5)
cam.mode = cam.mode.free
time.sleep(2)
cam.distance = cam.default_distance

2. I get an error when checking gear state after launch (or revert to launch) of an aircraft from the SPH. Once the gear is toggled (raised or lowered) the gear.state works fine, but until that first toggle i see the following. It is reproducible direct from the console by querying any gear state. Does it require some kind of initialisation i am missing?

    if gear.state == gear.state.retracted:
  File "<string>", line 1, in <lambda>
  File "C:\Users\petern\AppData\Local\Programs\Python\Python35-32\lib\site-packages\krpc\client.py", line 87, in _invoke
    raise RPCError(response.error)
krpc.error.RPCError: Operation is not valid due to the current state of the object

and it relates to this code:

gear_list = vessel.parts.landing_gear
    gear_up = 0
    gear_down = 0
    for gear in gear_list:
        if gear.state == gear.state.retracted:
            gear_up += 1

 

3. When a kerbal is EVA they still exist as a vessel, but vessel.control doesn't seem to have any effect. I am assuming that the game manages an EVA kerbal differently to a vessel, so this probably isn't supported. Is this assumption correct and is it something that could be included? Note though that issue #148 would probably achieve the same end by allowing controls to be mapped to key presses, and would allow things that are key driven like KAS/KIS also.

Anyway I think that is enough pestering for one night, so I shall leave it at that. Thank you again for all your help and the mod!

Cheers

Pete

 

Link to comment
Share on other sites

I'm having no luck trying to get krpc-clientgen to build client libraries for my extension to kRPC.  After bringing in all of the kOS and KRPC DLLs as dependencies, I get getting some variety of this error:
 

(venv) D:\git\KIPC\KSP\test>D:\git\kipc\python\venv\Lib\site-packages\krpctools\bin\ServiceDefinitions.Exe KIPC .\Assembly-CSharp.dll .\Assembly-CSharp-firstpass.dll .\KSPAssets.dll .\KSPCore.dll .\KSPUtil.dll .\kOS.dll .\kOS.Safe.dll .\ICSharpCode.SharpZipLib.dll .\KIPCPlugin.dll
Failed to load assembly '.\kOS.dll'.
Could not load file or assembly 'kOS, Version=0.20.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.

After fiddling around some, I managed to get this (more promising) error:

Unhandled Exception: KRPC.Service.ServiceException: System.String[] is not a valid Procedure parameter type, in KIPC.ResolveVessels
   at KRPC.Service.Scanner.ParameterSignature..ctor(String fullProcedureName, ProcedureParameter parameter)
   at KRPC.Service.Scanner.ProcedureSignature.<ProcedureSignature>m__0(ProcedureParameter x)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at KRPC.Service.Scanner.ProcedureSignature..ctor(String serviceName, String procedureName, String documentation, IProcedureHandler handler, GameScene gameScene, String[] attributes)
   at KRPC.Service.Scanner.ServiceSignature.AddProcedure(MethodInfo method)
   at KRPC.Service.Scanner.Scanner.GetServices()
   at ServiceDefinitions.MainClass.Main(String[] args)

which I then fixed, and am back to either my original error or it simply not finding the service.

Any idea on might be able to fix this?

Link to comment
Share on other sites

14 hours ago, dewin said:

Running under windows 10 with no problems.

I develop kRPC with a combination of Windows 10 and Ubuntu so shouldn't be any issue :wink:

23 hours ago, dewin said:

Any idea on might be able to fix this?

String[] is not a valid parameter type. You need to use an IList<String> for the KIPC.ResolveVessels function.

@PeteWasEre sorry I'm a bit bust at the moment, will try and find time to look at your questions later this week!

Edited by djungelorm
Link to comment
Share on other sites

8 hours ago, djungelorm said:

String[] is not a valid parameter type. You need to use an IList<String> for the KIPC.ResolveVessels function.

@PeteWasEre

Long since fixed, and I'm back to the problem of either it can't load kOS's assemblies or it can't find the service.  The latter occurs if I don't include the kOS DLLs in the command or I try my workaround of using a tool that strips all of the code from an assembly and just leaves behind the declarations.

I have my plugin working otherwise (pushed 0.1.1 last night) but the usage is currently limited to clients that don't need the service definitions.

Link to comment
Share on other sites

Hello djungelorm,

i'm still rubbing my eyes, this is an unbelievable mod!! :)

I got a problem which is sure located between my ears but i hope you could answer my questions. :D
So far i got the mod working and run my first basic commands while reading your fine manual.

1. At the moment im stuck with putting a vessel on the launchpad. Here is my python console:

>>> import krpc; conn = krpc.connect(name='Houston');
>>> conn.space_center.launch_vessel_from_vab(test)
Traceback (most recent call last):
  File "<pyshell#162>", line 1, in <module>
    conn.space_center.launch_vessel_from_vab(test)
NameError: name 'test' is not defined
>>>

So, why doesn't it find my saved vessel which is called test?

 

2. I tried to list all Vessels from the VAB to make sure its known but i get following error:

>>> conn.space_center.launchable_vessels (VAB)
Traceback (most recent call last):
  File "<pyshell#187>", line 1, in <module>
    conn.space_center.launchable_vessels (VAB)
NameError: name 'VAB' is not defined

 

Im pretty sure im doing something dumb but it would be kind if you could tell me what i'm doing wrong.

Thanks in advance!

Best wishes,
LtMtz

Edited by LtMtz
Link to comment
Share on other sites

6 hours ago, LtMtz said:

Im pretty sure im doing something dumb but it would be kind if you could tell me what i'm doing wrong.

Thanks in advance!

Best wishes,
LtMtz

Your Python code is looking for the value of a variable named 'test' rather than using "test" as a string.  Similar for VAB.

I'm guessing that you're new to Python.  You may want to familiarize yourself with the language itself before using kRPC -- there's a tutorial in the Python docs, or you might try one of these: (Disclaimer: I can't vouch for any of these, but I've heard the first one come up fairly often)

http://learnpythonthehardway.org

https://hourofpython.com

https://www.codecademy.com/learn/python

Or asking for good resources on the Python IRC channel: https://www.python.org/community/irc/

Link to comment
Share on other sites

Hi dewin,

thanks for the links, the third one is a nice one which i will use to get familiar with python!! Well i know a bit about programming but im new to python. Maybe i acted a bit sloppy as im used to uninitialized variables giving its name as string. Now with accurate set string it seems to work or at least giving other message... :D

import krpc
conn = krpc.connect(name='Houston')

print ('ok')
vss = 'VAB'
print (vss)
conn.krpc.GameScene.editor_vab
conn.space_center.launchable_vessels (vss)

 

output:
ok
VAB
Traceback (most recent call last):
  File "C:\Python35-32\test.py", line 8, in <module>
    conn.space_center.launchable_vessels (vss)
  File "<string>", line 1, in <lambda>
  File "C:\Python35-32\lib\site-packages\krpc\client.py", line 87, in _invoke
    raise RPCError(response.error)
krpc.error.RPCError: Procedure not available in game scene 'SpaceCenter'

 

Maybe i'm just a bit confused. Do i have to change scenes before i can get a list like i would do ingame? Thats the reason why i also tried  "conn.krpc.GameScene.editor_vab". Well both tries ended up with same error.

From what i read in the manual and forum it made me thinking that you can directly list or launch vessels while being in the space center scene. From what i learned I would expect the vessel-list output in the python shell. And when heading to a launch or another scene shouldn't it change the scene ingame? Or am I wrong here?

I also tested with and without mods, no difference.

I tested to launch and control a vessel that is already on the launchpad which is working flawless including controling, staging, autopilot, and so on. My actions are visible ingame as i write them into the shell.

No clue whats wrong in my space center ;.;

Link to comment
Share on other sites

7 hours ago, LtMtz said:

Do i have to change scenes before i can get a list like i would do ingame?

Yep, you need to be in the flight scene. Currently the APIs are only available in this scene. Making the APIs available from others scenes, like the space center view, is on the todo list for the next version!

On 7/13/2016 at 7:05 AM, dewin said:

Long since fixed, and I'm back to the problem of either it can't load kOS's assemblies or it can't find the service.  The latter occurs if I don't include the kOS DLLs in the command or I try my workaround of using a tool that strips all of the code from an assembly and just leaves behind the declarations.

I have my plugin working otherwise (pushed 0.1.1 last night) but the usage is currently limited to clients that don't need the service definitions.

Are you still having issues with this?

The tool works by loading each of the DLLs passed via the command line using Assembly.Load(...) and then scanning them for the named service. So you will need to pass the path to your service DLL, and the paths of all it's dependencies (which I guess is just KOS.dll?). The script assumes KRPC.dll is referenced (and has a copy of it) so you don't need to specify a path to that.

Link to comment
Share on other sites

10 minutes ago, djungelorm said:

Yep, you need to be in the flight scene. Currently the APIs are only available in this scene. Making the APIs available from others scenes, like the space center view, is on the todo list for the next version!

Are you still having issues with this?

The tool works by loading each of the DLLs passed via the command line using Assembly.Load(...) and then scanning them for the named service. So you will need to pass the path to your service DLL, and the paths of all it's dependencies (which I guess is just KOS.dll?). The script assumes KRPC.dll is referenced (and has a copy of it) so you don't need to specify a path to that.

I have.  Either it doesn't find the service (if I fail to reference KOS), or it complains about the KOS DLL: 

An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.

My passing KRPC.dll along was in efforts to try to get things to work.  (But I also use KRPC.SpaceCenter); at one point I passed it every single DLL I had in gamedata.

Link to comment
Share on other sites

Just noticed in your previous post that you're calling ServiceDefinitions directly. The intended way to do it is to call the "krpc-servicedefs" python script. For example:

pip install krpctools
krpc-servicedefs C:\path\to\ksp KIPC .\kOS.dll .\kOS.Safe.dll .\ICSharpCode.SharpZipLib.dll .\KIPCPlugin.dll

The script copies various DLLs to a temporary directory then runs ServiceDefinitions.exe. Simplifies the arguments slightly. You can run krpc-servicedefs --help for more info

Edit: just tried it on my linux machine, and the following command worked fine:

krpc-clientgen cpp KIPC --ksp /home/alex/workspaces/ksp/ksp-1.1.3.1289 KRPC.SpaceCenter.dll kOS.dll kOS.Safe.dll JsonFx.dll ICSharpCode.SharpZipLib.dll KIPCPlugin.dll

Will try on Windows.

Edited by djungelorm
Link to comment
Share on other sites

1 minute ago, djungelorm said:

Just noticed in your previous post that you're calling ServiceDefinitions directly. The intended way to do it is to call the "krpc-servicedefs" python script. For example:


pip install krpctools
krpc-servicedefs C:\path\to\ksp KIPC .\kOS.dll .\kOS.Safe.dll .\ICSharpCode.SharpZipLib.dll .\KIPCPlugin.dll

The script copies various DLLs to a temporary directory then runs ServiceDefinitions.exe. Simplifies the arguments slightly. You can run krpc-servicedefs --help for more info

Do you mean krpc-clientgen?

I tried that originally and went to calling servicedefs directly to to eliminate possible causes, but I've had no luck either way.

Discovered that there's also a krpc-servicedefs (hmm), and same result:

(venv) D:\git\KIPC>krpc-servicedefs KSP\ KSP\GameData\kOS\Plugins\kOS.dll KSP\gamedata\kos\Plugins\kOS.Safe.dll KSP\gamedata\kos\Plugins\ICSharpCode.SharpZipLib.dll KSP\GameData\KIPC\Plugins\KIPCPlugin.dll

Error: b"Failed to load assembly 'KSP\\gamedata\\kos\\Plugins\\kOS.Safe.dll'.\r\nCould not load file or assembly 'kOS.Safe, Version=0.20.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)\r\nAn attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.\r\n"

 

Link to comment
Share on other sites

Hi All -  Just trying this mod out, and having trouble getting it installed. 

I have my pip.exe in D:\Python\Scripts\pip.exe, and after pointing in the cmd shell to that file, with a space, and 'install krpc,' I get invalid Syntax error on the ':' just after the D drive designation.  

Ran as "D:\Python\Scripts\pip.exe  install krpc" on one line.   Syntax error on the ':'.   

Any ideas?  I've looked at several tutorials, even going back as far as to try installing pip, and the pip installation instructions I copied also gave me syntax errors.   Is there something I am possibly not importing, or have not yet installed to python, that I would need to recognize the commands?  

Cheers,
Bosun

Link to comment
Share on other sites

EDIT = Got it!   Thanks Djungelorm, i was needing an emulator to run it. 


Edit - After I download the krpc files from Github - do I place them in the library folder of Python?  

Edited by Bosun
Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

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...