浏览代码

Add GUID config handling, refine gamepad

GUID config is used for gamepad processing.
master
父节点
当前提交
ee7841cd31
共有 7 个文件被更改,包括 2000 次插入21 次删除
  1. +1846
    -0
      assets/gamecontrollerdb.txt
  2. +18
    -18
      docs/controls.md
  3. +2
    -0
      docs/reference/files/config-game.ini
  4. +104
    -1
      src/packages/config/IZ_config.c
  5. +1
    -0
      src/packages/config/IZ_config.h
  6. +24
    -2
      src/packages/game/input/IZ_joystick.c
  7. +5
    -0
      src/packages/game/input/IZ_joystick.h

+ 1846
- 0
assets/gamecontrollerdb.txt
文件差异内容过多而无法显示
查看文件


+ 18
- 18
docs/controls.md 查看文件

@@ -1,20 +1,20 @@
# Controls

| Action | Effect | Remarks |
|---------|-----------------------------------|--------------------------------------------------------------------------------------------------------|
| Up | Select Menu Item Up/Look Up | |
| Right | Select Menu Item Right/Move Right | |
| Down | Select Menu Item Down/Crouch | |
| Left | Select Menu Item Left/Move Left | |
| Affirm | Confirm Selected Option | |
| Negate | Go Back | |
| Action0 | Jump | When crouched, player will go down a solid-on-top ground. |
| Action1 | Primary Fire | Each weapon has firing characteristics, see below. |
| Action2 | Secondary Fire | Each weapon has firing characteristics, see below. |
| Action3 | Switch Weapon Mode | Press to select next weapon mode (cycle), hold then press Left/Right to set previous/next weapon mode. |
| Action4 | Switch Weapon | Press to select next weapon (cycle), hold then press Left/Right to set previous/next weapon. |
| Action5 | Item/Inventory | Hold to open inventory, double press to use current item. |
| Action6 | Switch Item | Press to select next item (cycle), hold then press Left/Right to set previous/next item. |
| Action7 | Take Cover | Enter doors, go between objects to hide from enemies. |
| Action8 | Sneak | Hold then press Left/Right to sneak. (do we need this control, or crouch is enough?) |
| Action9 | Reload | Reload always drops current clip regardless if there are rounds left. |
| Action | XInput | PS4 | Effect | Remarks |
|---------|---------:|---------:|-----------------------------------|--------------------------------------------------------------------------------------------------------|
| Up | A1+, A3+ | A1+, A4+ | Select Menu Item Up/Look Up | |
| Right | A0+, A2+ | A0+, A2+ | Select Menu Item Right/Move Right | |
| Down | A1-, A3- | A1-, A4- | Select Menu Item Down/Crouch | |
| Left | A0-, A2- | A0-, A2- | Select Menu Item Left/Move Left | |
| Affirm | B11 | | Confirm Selected Option | |
| Negate | B10 | | Go Back | |
| Action0 | B1 | B2 | Jump | When crouched, player will go down a solid-on-top ground. |
| Action1 | B0 | B1 | Primary Fire | Each weapon has firing characteristics, see below. |
| Action2 | B4 | | Secondary Fire | Each weapon has firing characteristics, see below. |
| Action3 | B3 | | Reload | Reload always drops current clip regardless if there are rounds left. |
| Action4 | B6 | | Switch Weapon Mode | Press to select next weapon mode (cycle), hold then press Left/Right to set previous/next weapon mode. |
| Action5 | B7 | | Switch Weapon | Press to select next weapon (cycle), hold then press Left/Right to set previous/next weapon. |
| Action6 | B8 | | Item/Inventory | Hold to open inventory, double press to use current item. |
| Action7 | B9 | | Switch Item | Press to select next item (cycle), hold then press Left/Right to set previous/next item. |
| Action8 | B13 | | Take Cover | Enter doors, go between objects to hide from enemies. |
| Action9 | B14 | | Sneak | Hold then press Left/Right to sneak. (do we need this control, or crouch is enough?) |

+ 2
- 0
docs/reference/files/config-game.ini 查看文件

@@ -5,6 +5,7 @@ MaxFps=30
[Joystick.0]
DeviceID=0
AxisThreshold=8000
GUID=00000000-0000-0000-0000-000000000000
[Joystick.0.ControlMapping]
Affirm=11
Negate=10
@@ -64,6 +65,7 @@ Username=Player 1
[Joystick.1]
DeviceID=1
AxisThreshold=8000
GUID=00000000-0000-0000-0000-000000000000
[Joystick.1.ControlMapping]
Affirm=11
Negate=10


+ 104
- 1
src/packages/config/IZ_config.c 查看文件

@@ -1,3 +1,4 @@
#include <SDL_guid.h>
#include "IZ_config.h"

const char* IZ_ConfigGetCommandlineOption(u8 argc, const char* argv[], const char* val) {
@@ -5,7 +6,6 @@ const char* IZ_ConfigGetCommandlineOption(u8 argc, const char* argv[], const cha
int c = argc;

while (--c > 0) {

if (!strncmp(argv[c], val, n)) {
if (!*(argv[c] + n) && c < argc - 1) {
/* coverity treats unchecked argv as "tainted" */
@@ -164,6 +164,57 @@ void IZ_ConfigOverrideString(IZ_ConfigItem* item, u8 argc, const char* argv[]) {
}
}

typedef bool IZ_ConfigLoadParamsGuidValidator(SDL_GUID);

void IZ_ConfigEnsureValidGuid(IZ_ConfigItem* item, SDL_GUID raw_value, SDL_GUID default_value) {
SDL_GUID* dest = item->dest;
if (item->validator) {
IZ_ConfigLoadParamsGuidValidator* validate = item->validator;
if (validate(raw_value)) {
// within valid values
*dest = raw_value;
return;
}
// outside valid values, we use default value
//
// TODO: what if the default value is also invalid?
*dest = default_value;
return;
}

// no validator, get whatever is the deserialized value
*dest = raw_value;
}

typedef SDL_GUID IZ_ConfigDeserializeGUID(const char*);

typedef void IZ_ConfigSerializeGUID(SDL_GUID, const char[128]);

void IZ_ConfigLoadGuid(IZ_ConfigItem* item, const char* config_path) {
static SDL_GUID raw_value;
static SDL_GUID default_value = {
.data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};

if (item->default_value) {
default_value = *((SDL_GUID *) item->default_value);
}

char buffer[128];
if (item->transformer.deserialize && item->transformer.serialize) {
IZ_ConfigDeserializeGUID* deserialize = item->transformer.deserialize;
IZ_ConfigSerializeGUID* serialize = item->transformer.serialize;
const char serialized_default_value[128];
serialize(default_value, serialized_default_value);
ini_gets(item->section, item->key, serialized_default_value, buffer, 128, config_path);
raw_value = deserialize(buffer);
} else {
ini_gets(item->section, item->key, "00000000-0000-0000-0000-000000000000", buffer, 128, config_path);
raw_value = SDL_GUIDFromString(buffer);
}
IZ_ConfigEnsureValidGuid(item, raw_value, default_value);
}

void IZ_ConfigLoad(IZ_ConfigItem item[], const char* config_path) {
u8 i;
for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) {
@@ -179,12 +230,58 @@ void IZ_ConfigLoad(IZ_ConfigItem item[], const char* config_path) {
break;
case IZ_CONFIG_TYPE_I32:
IZ_ConfigLoadI32(&item[i], config_path);
break;
case IZ_CONFIG_TYPE_GUID:
IZ_ConfigLoadGuid(&item[i], config_path);
break;
default:
break;
}
}
}

IZ_ConfigSaveItemResult IZ_ConfigSaveGuid(IZ_ConfigItem* item, const char* config_path) {
SDL_GUID dest = *((SDL_GUID*) item->dest);
if (item->validator) {
IZ_ConfigLoadParamsGuidValidator* validate = item->validator;
if (!validate(dest)) {
dest = *((const SDL_GUID*) item->default_value);
}
}

if (item->transformer.deserialize && item->transformer.serialize) {
IZ_ConfigSerializeGUID* serialize = item->transformer.serialize;
const char serialized_value[128];
serialize(dest, serialized_value);
if (!ini_puts(item->section, item->key, serialized_value, config_path)) {
return -1;
}
return 0;
}

char guid_str[128];
SDL_GUIDToString(dest, guid_str, 128);
if (!ini_puts(item->section, item->key, guid_str, config_path)) {
return -1;
}

return 0;
}

void IZ_ConfigOverrideGuid(IZ_ConfigItem* item, u8 argc, const char* argv[]) {
if (!item->cmdline_option) {
return;
}
const char* cmdline_buffer;
static SDL_GUID dest;
static SDL_GUID config_value;
config_value = *((SDL_GUID*) item->dest);
if((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item->cmdline_option))) {
dest = SDL_GUIDFromString(cmdline_buffer);
IZ_ConfigEnsureValidGuid(item, dest, config_value);
}
}

IZ_ConfigSaveResult IZ_ConfigSave(IZ_ConfigItem item[], const char* config_path) {
u8 i;
i64 problems = 0;
@@ -194,6 +291,9 @@ IZ_ConfigSaveResult IZ_ConfigSave(IZ_ConfigItem item[], const char* config_path)
case IZ_CONFIG_TYPE_STRING:
result = IZ_ConfigSaveString(&item[i], config_path);
break;
case IZ_CONFIG_TYPE_GUID:
result = IZ_ConfigSaveGuid(&item[i], config_path);
break;
case IZ_CONFIG_TYPE_U8:
result = IZ_ConfigSaveU8(&item[i], config_path);
break;
@@ -230,6 +330,9 @@ void IZ_ConfigOverride(IZ_ConfigItem item[], u8 argc, const char* argv[]) {
case IZ_CONFIG_TYPE_I32:
IZ_ConfigOverrideI32(&item[i], argc, argv);
break;
case IZ_CONFIG_TYPE_GUID:
IZ_ConfigOverrideGuid(&item[i], argc, argv);
break;
default:
break;
}


+ 1
- 0
src/packages/config/IZ_config.h 查看文件

@@ -12,6 +12,7 @@ typedef enum {
IZ_CONFIG_TYPE_U8,
IZ_CONFIG_TYPE_U16,
IZ_CONFIG_TYPE_I32,
IZ_CONFIG_TYPE_GUID,
} IZ_ConfigType;

typedef struct {


+ 24
- 2
src/packages/game/input/IZ_joystick.c 查看文件

@@ -106,6 +106,13 @@ void IZ_JoystickHandleHatEvents(IZ_Action* action, SDL_Event e) {
void IZ_JoystickHandleButtonEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) {
u8 control_index;


SDL_JoystickGUID joystick_guid = SDL_JoystickGetGUID(SDL_JoystickFromInstanceID(e.jbutton.which));
for (u8 zz = 0; zz < 16; zz += 1) {
printf("%02x", joystick_guid.data[zz]);
}
printf("\n");

for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
u8 normalized_button = e.jbutton.button;

@@ -167,8 +174,9 @@ void IZ_JoystickBindStateToConfig(IZ_JoystickState(* state)[IZ_PLAYERS], IZ_Conf
u8 base_index = (player_index * (IZ_CONTROLS - 4 + 2));
config_items[base_index].dest = &((*state)[player_index].config.device_id);
config_items[base_index + 1].dest = &((*state)[player_index].config.axis_threshold);
config_items[base_index + 2].dest = &((*state)[player_index].config.guid);
for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
config_items[base_index + 2 + (control_index - 4)].dest = &((*state)[player_index].config.control_mapping[control_index]);
config_items[base_index + 3 + (control_index - 4)].dest = &((*state)[player_index].config.control_mapping[control_index]);
}
}
}
@@ -209,10 +217,23 @@ void IZ_JoystickInitializeConfigItems(IZ_ConfigItem config_items[]) {
NULL,
};

config_items[base_index + 2] = (IZ_ConfigItem) {
IZ_CONFIG_TYPE_STRING,
sizeof(u16),
main_section_name,
"GUID",
NULL,
&IZ_JOYSTICK_DEFAULT_STATE[player_index].config.guid,
NULL,
NULL,
};

// todo add game controller GUID for determining mappings

control_mapping_section_name = SDL_malloc(sizeof(char) * 64);
sprintf(control_mapping_section_name, "Joystick.%d.ControlMapping", player_index);
for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
config_items[base_index + 2 + (control_index - 4)] = (IZ_ConfigItem) {
config_items[base_index + 3 + (control_index - 4)] = (IZ_ConfigItem) {
IZ_CONFIG_TYPE_U8,
sizeof(u8),
control_mapping_section_name,
@@ -252,6 +273,7 @@ IZ_ProcedureResult IZ_JoystickInitialize(IZ_JoystickState(* state)[IZ_PLAYERS],
return -2;
}

SDL_GameControllerAddMappingsFromFile("assets/gamecontrollerdb.txt");
u8 player_index;
u8 joysticks_count = SDL_NumJoysticks();
for (player_index = 0; player_index < joysticks_count; player_index += 1) {


+ 5
- 0
src/packages/game/input/IZ_joystick.h 查看文件

@@ -3,6 +3,7 @@

#include <SDL_stdinc.h>
#include <SDL_joystick.h>
#include <SDL_gamecontroller.h>
#include <SDL_events.h>
#include <minIni.h>
#include "../../config/IZ_config.h"
@@ -24,6 +25,7 @@ typedef enum {
typedef struct {
u16 axis_threshold;
SDL_JoystickID device_id;
SDL_GUID guid;
IZ_PadButton control_mapping[IZ_CONTROLS];
} IZ_JoystickConfig;

@@ -55,6 +57,9 @@ static const IZ_JoystickState IZ_JOYSTICK_DEFAULT_STATE[IZ_PLAYERS] = {
},
.axis_threshold = 8000u,
.device_id = 0,
.guid = {
.data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}
},
.device = NULL,
},


正在加载...
取消
保存