Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
343 changes: 343 additions & 0 deletions README.es-ES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
# UnityCommandLineInterface

[![openupm](https://img.shields.io/npm/v/com.redsaw.commandline?label=openupm&registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.redsaw.commandline/)

[中文文档](./README-ch.md)

## Resumen
Este proyecto es una consola de comandos interna para juegos, utilizada generalmente para ejecutar comandos cortos o establecer/obtener propiedades.

<div align=center>
<img src="./Res/screen-shot.png" style="zoom:80%" />
</div>

https://github.com/529324416/UnityCommandLineInterface/assets/30776995/a2290fff-ffa5-421f-8a4a-a5274e9c6d87

## Características:
- **Fácil de usar**, no requiere un aprendizaje extenso.
- **Ligero**, sin dependencias.
- **Sugerencias de texto de entrada**.
- **Soporte para todas las versiones de Unity**.
- **Altamente desacoplado**.
- **Fácil de portar a otras plataformas**.

## Uso

## 1. Registro de Comandos

Registrar un comando es sencillo, solo necesitas añadir un atributo `Command` a tu método estático.

```csharp
[Command("my_cmd")]
public static void SomeMethod(){
/* hacer algo aquí .. */
}
```

El sistema también permite añadir métodos de instancia, pero ahora que el sistema cuenta con la nueva funcionalidad **CommandProperty**, registrar métodos de instancia resulta innecesario.

## 2. Ejecución de Comandos

Los comandos pueden ejecutarse de dos maneras; la primera es así:

```
your_command args1 args2
```

Pero también puedes ejecutarlo como si fuera un método:

```
your_command(args1, args2)
```

La primera forma facilita la ejecución rápida de un comando, y la segunda proporciona la capacidad de acceder a los miembros del valor de retorno, como se muestra a continuación:

```
get_enemy("slime").Jump()
```

## 3. Variables de Consola

La nueva consola te permite registrar una variable de consola y acceder a ella mediante `@`, lo que hace que el sistema de comandos sea muy flexible. Suponiendo que tienes un objeto como este:

```csharp
public class Player : MonoBehaviour{

public int health = 100;

public void Jump(){
// código para saltar..
}
}
```
Puedes configurar una variable estática y añadirle el atributo `CommandProperty` para registrarla como variable de consola:

```csharp
public class Player: MonoBehaviour{

[CommandProperty("player")]
public static Player Instance;
}
```
(Debes asignar una instancia de `Player` a la variable estática al iniciar el juego).

Luego puedes acceder a los miembros internos de `Player`; todo esto se basa en el Sistema de Reflexión de C#. Puedes usar los comandos de la siguiente manera:

```
@player.health = 100
@player.Jump()
```

Del mismo modo, en cualquier lugar que necesites una variable, puedes usar `@` para referenciarla, por ejemplo, como parámetro de otros comandos:

```
@enemy.Atk(@player)
```

El atributo `CommandProperty` puede añadirse a un Campo (Field) o a una Propiedad (Property), lo que significa que la variable de consola puede devolver diferentes valores, como "el NPC más cercano al jugador":

```csharp
[CommandProperty("nearest")]
public static Npc NearestNpc{
get{
// código para obtener el npc más cercano..
}
}
```

## 4. Acceso a variables de consola

Puedes acceder o sobrescribir miembros de una variable de consola a través de `.` o `[]`.

```
@player.DoSomething()
@player.buffs["buff_id"].AddTime(100)
@enemies["slime"] = @new_slime
```

Por supuesto, el acceso es continuo, similar a un lenguaje de programación normal:

```
@something.member.sub_member["elements"].member.sub_member.field.function().member
```

El uso de `[]` tiene una particularidad: verificará si el miembro objetivo es un objeto de secuencia, como un Array o List; si es así, requerirá que la expresión dentro de `[]` sea un valor Entero.

Los Dictionary soportan más tipos de claves, por lo que el rango de juicio del diccionario es más amplio.

```
@some_dict[@non_string_type] = get_something()
```

Por ejemplo, si el tipo de clave de tu diccionario no es un string, puedes usar otras variables de consola como clave para leer o escribir.

## 5. Análisis de Valores (Value Parse)

El CommandSystem soporta únicamente 5 tipos de valores básicos.

```
string
float
int
bool
null
```

Puedes considerar estos como meta-tipos; pueden ser analizados por el sistema de comandos directamente y, en general, son suficientes. Sin embargo, si deseas que la consola pueda analizar diferentes tipos de datos, puedes hacerlo registrando un analizador de valores (value parser).

Por ejemplo, la posición del jugador podría ser de tipo `Vector3`, y quizás desees establecer la posición del jugador así:

```
@player.pos = "1. 1. 1."
```

Obviamente, los strings no se pueden convertir automáticamente a `Vector3`. Si realmente necesitas hacer esto, puedes registrar un `ValueParser` de la siguiente manera:

```csharp

[CommandValueParser(typeof(Vector3))]
static bool ParseFunction(string input, out object data){
// código utilizado para analizar tu cadena de entrada
}
```

La lógica de análisis es totalmente libre. Por ejemplo, puedes analizar 'revival_point' para convertirlo en un `Vector3`:

```csharp
static bool ParseFunction(string input, out object data){
if(input == "revival_point"){
data = Vector3.zero;
return true;
}
// otros análisis aquí ..

data = default;
return false;
}
```

Entonces puedes usar el comando de la siguiente manera:

```
@player.pos = "revival_point"
```

Las comillas dobles aquí no son necesarias, pero no se recomienda hacerlo así. El sistema primero considerará 'revival_point' como un comando e intentará ejecutarlo para obtener el valor de retorno. El sistema intentará analizarlo como `Vector3` solo si no encuentra un comando llamado 'revival_point'.

```
@player.pos = revival_point
```

Por lo tanto, es mejor no usar comandos tan ambiguos.

El `ValueParser` se utiliza generalmente en situaciones especiales o tipos de datos complejos. Si quieres analizar un `Vector3`, la forma correcta es registrar un comando como este:

```csharp
[Command("v3")]
public static Vector3 BuildVector3(float x, float y, float z){
return new Vector3(x, y, z);
}
```

Y usarlo de la siguiente manera:

```
@player.pos = v3(0, 0, 0)
```

## 6. Registro de Información de Depuración (Debug Infos)

Si deseas mostrar la información de un objeto objetivo, por ejemplo, simplemente ingresando '@player' en la consola.

```
@player
```

La consola podría imprimir la información del jugador como se muestra a continuación:

![Untitled](./Res/Untitled.png)

Para definir la estructura de la información, puedes añadir un atributo `DebugInfo` al campo o propiedad objetivo:

```csharp
public class Player : MonoBehaviour{

[DebugInfo]
public int health = 100;
}
```

De esta manera, al ingresar `@player` en la consola, obtendrás directamente todo el DebugInfo del jugador, y la salida será la siguiente:

```
---------- Player start ----------
>Player.health: 100
---------- Player end ----------
```

Puedes configurar un título y un color para ello:

```csharp
[DebugInfo("custom_title", Color = "#ff0000")]
```

### 6.1 Rastreo de Clases Padre

El sistema rastreará todas sus clases padre y mostrará el `DebugInfo` de la clase padre original hacia la clase objetivo uno por uno.

```csharp
public class A{
[DebugInfo]
public int someInt = 999;
}

public class B{
[DebugInfo]
public float someFloat = 12.3;
}

public class C{
[DebugInfo]
public string someStr = "Hello World!";
}
```

Si intentas mostrar el `DebugInfo` de C, obtendrás:

```
---------- C start ----------
>A.someInt: 999
>B.someFloat: 12.3
>C.someStr: Hello World!
---------- C end ----------
```

### 6.3 DebugInfo de miembros complejos

Si el miembro que ha sido registrado como `DebugInfo` también posee `DebugInfos` internos, puedes añadir un atributo `DebugObject` a la clase objetivo:

```csharp
public class A{
[DebugInfo("my_object")]
public B b = new B();
}

[DebugObject]
public class B : MonoBehaviour{
[DebugInfo("name")]
public string Name => this.gameObject.name;

[DebugInfo]
public string age = 25;
}
```

Si intentas imprimir A, obtendrás esto:

```
---------- C start ----------
>----[B]
> B.name: "instanceB"
> B.age: 25
---------- C end ----------
```

Sin embargo, de esta forma puede haber referencias circulares de datos (por ejemplo, B referencia a C y C referencia a B), por lo que puedes establecer una profundidad para limitar estas referencias. Si la profundidad excede el límite, el sistema descartará la información adicional; el límite de profundidad predeterminado es 4.

## 7. Sugerencias de Entrada

No hay nada que describir.

![Untitled](./Res/Untitled%20(1).png)

## 8. Registros de Consola (Console Logs)

El nuevo sistema ha desacoplado los comportamientos de salida y renderizado, lo que significa que la consola solo guarda el registro pero no le importa cómo se renderiza. No obstante, debes proporcionar un `logType` para marcar los registros. Puedes configurarlo al inicializar la consola del juego.

```csharp
/* inicializar consola */
console = new ConsoleController<LogType>(
consoleRenderer,
new UserInput(),

inputHistoryCapacity: inputHistoryCapacity,
commandQueryCacheCapacity: commandQueryCacheCapacity,
alternativeCommandCount: alternativeCommandCount,
shouldRecordFailedCommand: shouldRecordFailedCommand,
outputWithTime: shouldOutputWithTime,
outputStackTraceOfCommandExecution: shouldOutputVMExceptionStack
);
```
Y puedes decidir dónde guardar los registros.

## Otros

### Versiones de UnityEngine

Unity 2018.03+

Soporta todas las versiones.

### Soporte de Funciones: Cálculo Básico

El sistema está diseñado para trabajos de depuración convenientes, por lo que su propósito no es ser un lenguaje de programación completo. Por lo tanto, actualmente no soporta operaciones básicas como operaciones matemáticas o lógicas. Si existe la necesidad de esta función, puedes proponerla en Github y, si es realmente necesario, la implementaré.