I'm currently working on a project to bring adaptive interactions to game worlds, as a casy-study we chose to use OpenClonk due to it's large set of interactions and it being open source.
We're already quite far in this project and have created a modified version of the OpenClonk server to run dedicated and log interactions, the basic idea behind this is as follows:
1) For a player in a game, log every action (e.g. Player shoots Gun, or, Player uses Shovel, or, Player kills OtherPlayer)
2) For every logged action, determine it's score according to an initial value (which is usually the same for every action) and a time-based decay (newer, and thus, more frequent actions should have a high score)
3) Store every score value in a matrix with rows as player sessions and columns as action scores
4) Run cluster-analysis to find clusters, or, styles of play
5) Train Hidden Markov Models to use them for classification (Baum-Welch and Viterbi)
6) Classify a player according to it's behavior in a game, and adapt to this behavior (e.g. by using a game design editor, for OpenClonk we'll be using Entika, introduced here)
(More details are described in this paper)
The way I've currently implemented this is by hooking into both the C4Object and C4Effect (SetAction and New), which, as far as I can see now with the little data we collected, seems to cover all actions (at least the actions that we're interested in).
An Update call is made to update the scores of all actions continuously.
I was wondering as to what your suggestions would be to further enhance the collection of interactions in OpenClonk.
What might yield a good result would be to hook into the script execution and catch the "call" events to filter out when "OnUse" is called in an item since that is a very common entry point for actions (using Axe, Shovel, shooting arrows, etc..)
And another point is difference between games, for examples in some of the races a player would use one item only (example Boompack, or wind bag) whereas in other rounds the whole spectra of weapons we currently have. Don't you think this will somehow mess up these player profiles you are talking about? Also the difference in playing styles between melees and settlement rounds is really large, how do you plan to capture this?
Anyway, good luck with the project :)
@Maikel: About the trustworthy analysis, we have seen that in previous experiments apart from OpenClonk there was a tipping point at around 60 play sessions were we could see clusters (play styles) form in our analysis. Since OpenClonk features more complex data, this point with OpenClonk will yield more sessions. We're monitoring the data that we collect and run our analysis manually in the beginning, this to allow us to evaluate the results of our analysis.
@Sven2: Sorry about the hack protection, I've seen your comments, it seems that we currently cover every action that we're interested in, I like the idea of setting up some sort of competion but due to time constraints we're (unfortunately) not able to execute this :-(
@Zapper: The current implementation hooks into C4Object and C4Effect and intercepts SetAction, which seem to cover the C4Action/C4Object part of the actions, C4Effect interception in New seems to cover the rest
>@Zapper: The current implementation hooks into C4Object and C4Effect and intercepts SetAction, which seem to cover the C4Action/C4Object part of the actions, C4Effect interception in New seems to cover the rest
This is more because most of the usage events ingame use some sort of C4Effect for particles, timing, etc.. However, ALL use the OnUse callback.
But you are right, since most actions ingame involve some sort of timer/graphical effect, catching C4Effect might cover a good amount of the cases
> I like the idea of setting up some sort of competion but due to time constraints we're (unfortunately) not able to execute this :-(
We will probably have competitions once we have the league server set up anyway. The game already supports all the mechanisms inherited from Clonk Rage. It's just that we don't have the server backend set up for OpenClonk yet.
The league server automatically receives records of all rounds that are played (independent from the server!!) for cheat-protection purposes. A custom-built engine (like yours) could replay ALL of the records with the hooks in the right places and analyze the data. This would make you not depend on people playing games on your server.
The league source code is still closed source and we are waiting for it to be put under a license that allows us to use it. Only after that, we can start to incorporate the league into our website, and get it running which will also take some time. Count with not less than a few months.
I'm working on the binding with out semantics editor.
If you want to change them at runtime, to stay in sync with the clients who don't have your engine, you will have to send a CID_Script control packet that changes the values. E.g. define global variables in script in your local definition (e.g. static g_rope_length = 100;), use those in the scripts (SetMaxLength(g_rope_length)) and send modifications via network (::Control.DoInput(CID_Script, new C4ControlScript("g_rope_length=200", -1, true), CDT_Decide);).
> ::Control.DoInput(CID_Script, new C4ControlScript("g_rope_length=200", -1, true), CDT_Decide);
by the way this doesn't work anymore with the recent changes I made, but it should still be fine for 5.3.3
1) We learn that OpenClonk has play styles S1 ... S5
3) A game designer defines that property rope_length for the RopeGun object for style S1 should be L
4) At runtime, we learn that player P1 shows S1 behavior, we match S1 as P1's style
5) Whenever P1 uses the RopeGun, the rope_length value will be L
(A very minimal example)
So, the implementation of SetMaxLength will be "::Control.DoInput(CID_Script, new C4ControlScript("g_rope_length=200", -1, true), CDT_Decide);" right?
You can send anything that is valid C4Script. For example, you could make g_rope_length an array of player numbers and then modify only the indexed value.
Let's say you copied the GrappleBow into your scenario. You then modify the grapple bow rope script (GrappleBow.ocd\Rope.ocd\Script.c). The rope length is set in the Connect function:
public func Connect(object obj1, object obj2)
[... rest of the function]
Now GetRopeLengthForPlayer would be a function that queries a global variable:
func GetRopeLengthForPlayer(int plr)
// Default length for non-player hooks (e.g. AI clonks)
if (plr<0) return 100;
// init array on first call
if (!g_rope_lengths) g_rope_lengths = ;
if (!g_rope_lengths[plr]) g_rope_lengths[plr] = 100; // default length
// return current rope length for player
To change these values from the engine, you could write a helper function:
global func SetRopeLengthForPlayer(int plr, int new_length)
// init array on first call
if (!g_rope_lengths) g_rope_lengths = ;
// store new length
g_rope_lengths[plr] = new_length;
Finally, you can call this function on all clients running this C++ code on the host:
::Control.DoInput(CID_Script, new C4ControlScript(FormatString("SetRopeLengthForPlayer(%d,%d)", player_number, new_rope_length).getData(), -1, true), CDT_Decide);
I haven't tested this; e.g. I'm not sure if obj2->GetController() will get you the proper player number. You should check by logging this. You can use calls to Log like this:
Log("Current rope length array is: %v", g_rope_lengths);
Log("Variable plr is: %v", plr);
Log stuff is written to the OpenClonk.log and displayed in the console. The engine counterpart is called "LogF" in C++ code and is called analogous to e.g. fprintf.
Static const is replaced by its value at compile time; static variables will be used at runtime. You run into trouble if you try to use them e.g. in ActMaps, which are initialized at compile time. To change ActMap values at runtime, you would have to create a copy of the ActMap and then change it in the object instance.
Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill