This plugin provides parsing/formatting for different data formats. It only supports Json for now. It can be used with Redscript and CET.
- Cyberpunk 2077 v2.2
- Redscript 0.5.27+
- Cyber Engine Tweaks 1.34.0+
- Install requirements:
- RED4ext v1.26.0+
- Extract the latest archive into the Cyberpunk 2077 directory.
This plugin can be used when writing a RED4ext plugin with RedLib. You can find a C++ API wrapper in branch api.
All Json features are defined in module RedData.Json
. You need to import it
with:
import RedData.Json.*
ParseJson(text: String) -> ref<JsonVariant>
e.g. with Json data:
{
"name": "RedData",
"version": 1,
"isEnabled": true,
"pi": 3.14159265358979323846,
"items": [2077, 13.37, true, "Cyberpunk"],
"i18n": {
"en-US": "Hello",
"fr-FR": "Bonjour"
}
}
You can parse Json content of a String
like this:
// ...
let json = ParseJson("<json data from example above>");
if !IsDefined(json) {
LogChannel(n"Error", s"Failed to parse Json.");
return;
}
if !json.IsObject() {
LogChannel(n"Error", s"Expect root of Json document to be an object.");
return;
}
// ...
IsUndefined() -> Bool
IsNull() -> BoolIsBool() -> Bool
IsInt64() -> Bool
IsUint64() -> Bool
IsDouble() -> Bool
IsString() -> BoolIsArray() -> Bool
IsObject() -> BoolToString(opt indent: String) -> String
You can format Json data to a String
. It will format output as minified Json
by default. You can pretty format Json with spaces and/or tabulations using
indent
argument.
// ...
LogChannel(n"Info", s"Minified: \(json.ToString())");
LogChannel(n"Info", s"Pretty (two spaces): \(json.ToString(" "))");
LogChannel(n"Info", s"Pretty (tab): \(json.ToString("\t"))");
Note
Order of keys in a JsonObject
is not preserved due to underlying
optimization.
Warning
Using other characters than spaces and tabulations is not allowed. It will fallback to minified Json instead.
GetKeys() -> array<String>
GetValues() -> array<ref<JsonVariant>>HasKey(key: String) -> Bool
GetKey(key: String) -> ref<JsonVariant>
SetKey(key: String, value: ref<JsonVariant>) -> Void
RemoveKey(key: String) -> BoolGetKeyBool(key: String) -> Bool
GetKeyInt64(key: String) -> Int64
GetKeyUint64(key: String) -> Uint64
GetKeyDouble(key: String) -> Double
GetKeyString(key: String) -> StringSetKeyNull(key: String) -> Void
SetKeyBool(key: String, value: Bool) -> Void
SetKeyInt64(key: String, value: Int64) -> Void
SetKeyUint64(key: String, value: Uint64) -> Void
SetKeyDouble(key: String, value: Double) -> Void
SetKeyString(key: String, value: String) -> VoidClear() -> Void
Get values:
// ...
let obj = json as JsonObject;
let name = obj.GetKeyString("name");
let version = obj.GetKeyInt64("version");
let isEnabled = obj.GetKeyBool("isEnabled");
let pi = obj.GetKeyDouble("pi");
// Same as:
// let name = obj.GetKey("name").GetString();
// let version = obj.GetKey("version").GetInt64();
// let isEnabled = obj.GetKey("isEnabled").GetBool();
// let pi = obj.GetKey("pi").GetDouble();
Get a list of keys:
// ...
let keys = obj.GetKeys();
// keys == ["name", "version", "isEnabled", "pi", "items", "i18n"]
Get a list of values:
// ...
let values = obj.GetValues();
// values[0].GetString() == "RedData"
// values[1].GetInt64() == 1
// values[2].GetBool() == true
// values[3].GetDouble() == 3.14159265358979323846
// values[4] == [...]
// values[5] == {...}
Test whether a key is present:
// ...
let hasName = obj.HasKey("name");
let hasUnknown = obj.HasKey("unknown");
// hasName == true
// hasUnknown == false
GetSize() -> Uint32
GetItem(index: Uint32) -> ref<JsonVariant>
SetItem(index: Uint32, value: ref<JsonVariant>) -> Void
RemoveItem(index: Uint32) -> Bool
AddItem(value: ref<JsonVariant>) -> Void
InsertItem(index: Uint32, value: ref<JsonVariant>) -> VoidGetItemBool(index: Uint32) -> Bool
GetItemInt64(index: Uint32) -> Int64
GetItemUint64(index: Uint32) -> Uint64
GetItemDouble(index: Uint32) -> Double
GetItemString(index: Uint32) -> StringSetItemNull(index: Uint32) -> Void
SetItemBool(index: Uint32, value: Bool) -> Void
SetItemInt64(index: Uint32, value: Int64) -> Void
SetItemUint64(index: Uint32, value: Uint64) -> Void
SetItemDouble(index: Uint32, value: Double) -> Void
SetItemString(index: Uint32, value: String) -> VoidAddItemNull() -> Void
AddItemBool(value: Bool) -> Void
AddItemInt64(value: Int64) -> Void
AddItemUint64(value: Uint64) -> Void
AddItemDouble(value: Double) -> Void
AddItemString(value: String) -> VoidInsertItemNull(index: Uint32) -> Void
InsertItemBool(index: Uint32, value: Bool) -> Void
InsertItemInt64(index: Uint32, value: Int64) -> Void
InsertItemUint64(index: Uint32, value: Uint64) -> Void
InsertItemDouble(index: Uint32, value: Double) -> Void
InsertItemString(index: Uint32, value: String) -> VoidClear() -> Void
Get items:
// ...
let items = obj.GetKey("items") as JsonArray;
let year = items.GetItemInt64(0u);
let elite = items.GetItemDouble(1u);
let theWay = items.GetItemBool(2u);
let title = items.GetItemString(3u);
// Same as:
// let year = items.GetItem(0u).GetInt64();
// let elite = items.GetItem(1u).GetDouble();
// let theWay = items.GetItem(2u).GetBool();
// let title = items.GetItem(3u).GetString();
Get the number of items:
let size: Uint32 = items.GetSize();
Note: arrays are iterated from 1 to N when using Lua. In this case, you must iterate from 0 to N - 1.
FromJson(json: ref<JsonObject>, type: CName) -> ref<IScriptable>;
You can create a class from Json. It will match properties of the class with keys from Json data. The name of a property/key is case-sensitive.
public class MessageDto {
let id: Uint64;
let createdAt: Int32;
let author: ref<UserDto>;
let text: String;
}
public class UserDto {
let id: Uint64;
let firstName: String;
let lastName: String;
let permissions: array<String>;
}
let json = ParseJson("<Json data>") as JsonObject;
let message = FromJson(json, n"MessageDto") as MessageDto;
// ^
// | CName of the class to format Json to.
LogChannel(n"Info", s"text: \"\(message.text)\"");
This feature supports the following types:
Bool
Int8
,Int16
,Int32
,Int64
Uint8
,Uint16
,Uint32
,Uint64
Float
,Double
String
,CName
,ResRef
,TweakDBID
ref<T>
,array<T>
When property is:
- a weak reference: the value is always set to
null
. - a strong reference: the value is set with a new instance built from the Json
data, or it fallbacks to
null
. - an array: the value is set with an array built from the Json data.
Note
Type of array can be any of the supported types above, but it does not support arrays within arrays.
ToJson(object: ref<IScriptable>) -> ref<JsonObject>;
You can create Json data from a class. It will create a JsonObject
based on
properties of the object.
// ...
let message = new MessageDto();
message.id = 42;
message.createdAt = 1337;
message.author = null;
message.text = "Hello world!";
let json = ToJson(message);
LogChannel(n"Info", s"json: \(json.ToString(" "))");
// It should log:
// {
// "id": 42,
// "createdAt": 1337,
// "author": null,
// "text": "Hello world!"
// }
This feature supports the following types:
Bool
Int8
,Int16
,Int32
,Int64
Uint8
,Uint16
,Uint32
,Uint64
Float
,Double
String
,CName
ref<T>
,array<T>
ResRef
and TweakDBID
are not supported because they cannot be transformed
back to a String
.
Note
Type of an array can be any of the supported types above, but it does not support arrays within arrays.
You can create JsonObject/JsonArray.
// ...
let json = new JsonObject();
json.SetKeyString("name", "RedData");
json.SetKeyBool("isEnabled", true);
json.SetKeyDouble("version", 2.12);
let items = new JsonArray();
items.AddItemNull();
items.AddItemBool(true);
items.AddItemInt64(2077);
items.AddItemDouble(13.37);
items.AddItemString("Welcome to Night City!");
json.SetKey("items", items);
let text = json.ToString("\t");
LogChannel(n"Info", s"Json:");
LogChannel(n"Info", text);
Contributions are welcome, feel free to fill an issue or a PR.
- Install requirements:
- CMake v3.27+
- Visual Studio Community 2022+
- red-cli v0.2.2+
- Configure project with:
cmake -G "Visual Studio 17 2022" -A x64 -S . -B build
- Build in debug mode:
cmake --build build --target RedData --config Debug
It will execute red-cli install
for you using a CMake custom command.
- Run game.
- Open CET, show Game Log popup.
- Output should show tests result.
- Build in release mode:
cmake --build build --target RedData --config Release
It will execute red-cli pack
for you using a CMake custom command. You should
find an archive RedData-vX.Y.Z.zip
in the root directory, ready to release.