mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-22 01:52:43 +00:00
Merge 054d7f8a66 into de25c5437b
This commit is contained in:
commit
f7bc3bfb7e
51 changed files with 3116 additions and 567 deletions
4
Makefile
4
Makefile
|
|
@ -517,6 +517,10 @@ ifeq ($(DISCORD_SDK),1)
|
|||
SRC_DIRS += src/pc/discord
|
||||
endif
|
||||
|
||||
ifeq ($(WINDOWS_BUILD),0)
|
||||
SRC_DIRS += src/pc/linenoise
|
||||
endif
|
||||
|
||||
SRC_DIRS += src/pc/mumble
|
||||
|
||||
ULTRA_SRC_DIRS := lib/src lib/src/math lib/asm lib/data
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ in_files = [
|
|||
"src/game/mario_step.h",
|
||||
"src/game/mario.h",
|
||||
"src/game/rumble_init.h",
|
||||
"src/pc/commands.h",
|
||||
"src/pc/djui/djui_popup.h",
|
||||
"src/pc/network/network_utils.h",
|
||||
"src/pc/djui/djui_console.h",
|
||||
|
|
@ -86,6 +87,7 @@ in_files = [
|
|||
override_allowed_functions = {
|
||||
"src/audio/external.h": [ " play_", "fade", "current_background", "stop_", "sound_banks", "drop_queued_background_music", "set_sound_moving_speed", "background_music_default_volume", "get_sound_pan", "sound_get_level_intensity", "set_audio_muted" ],
|
||||
"src/game/rumble_init.h": [ "queue_rumble_", "reset_rumble_timers" ],
|
||||
"src/pc/commands.h": [ "command_message_create" ],
|
||||
"src/pc/djui/djui_popup.h": [ "create" ],
|
||||
"src/pc/djui/djui_language.h": [ "djui_language_get" ],
|
||||
"src/pc/djui/djui_panel_menu.h": [ "djui_menu_get_rainbow_string_color" ],
|
||||
|
|
|
|||
|
|
@ -2751,6 +2751,9 @@ DIALOG_COUNT = 170 --- @type DialogId
|
|||
--- | `DIALOG_169`
|
||||
--- | `DIALOG_COUNT`
|
||||
|
||||
--- @type integer
|
||||
MAX_CONSOLE_INPUT_LENGTH = 500
|
||||
|
||||
CONSOLE_MESSAGE_INFO = 0 --- @type ConsoleMessageLevel
|
||||
CONSOLE_MESSAGE_WARNING = 1 --- @type ConsoleMessageLevel
|
||||
CONSOLE_MESSAGE_ERROR = 2 --- @type ConsoleMessageLevel
|
||||
|
|
|
|||
|
|
@ -3789,6 +3789,12 @@ function update_character_anim_offset(m)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param message string
|
||||
--- @param level? ConsoleMessageLevel
|
||||
function command_message_create(message, level)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param message string
|
||||
--- Creates a `message` in the game's chat box
|
||||
function djui_chat_message_create(message)
|
||||
|
|
|
|||
|
|
@ -126,6 +126,19 @@ function update_chat_command_description(command, description)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param command string The command to run. Should be easy to type
|
||||
--- @param description string Should describe what the command does and how to use it
|
||||
--- @param func fun(msg:string): boolean Run upon activating the command. Return `true` to confirm the command has succeeded
|
||||
function hook_console_command(command, description, func)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param command string The command to change the description of
|
||||
--- @param description string The description to change to
|
||||
function update_console_command_description(command, description)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param hookEventType LuaHookedEventType When a function should run
|
||||
--- @param func fun(...: any): any?, any? The function to run
|
||||
--- Different hooks can pass in different parameters and have different return values. Be sure to read the hooks guide for more information.
|
||||
|
|
@ -407,13 +420,13 @@ end
|
|||
--- @param command string
|
||||
--- @vararg integer | string | Gfx | Texture | Vtx Parameters for the command
|
||||
--- Sets a display list command on the display list given.
|
||||
---
|
||||
---
|
||||
--- If `command` includes parameter specifiers (subsequences beginning with `%`), the additional arguments
|
||||
--- following `command` are converted and inserted in `command` replacing their respective specifiers.
|
||||
---
|
||||
---
|
||||
--- The number of provided parameters must be equal to the number of specifiers in `command`,
|
||||
--- and the order of parameters must be the same as the specifiers.
|
||||
---
|
||||
---
|
||||
--- The following specifiers are allowed:
|
||||
--- - `%i` for an `integer` parameter
|
||||
--- - `%s` for a `string` parameter
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ extern "C" {
|
|||
#include "game/moving_texture.h"
|
||||
#include "pc/djui/djui_console.h"
|
||||
#include "pc/fs/fmem.h"
|
||||
#include "pc/debuglog.h"
|
||||
}
|
||||
|
||||
#define FUNCTION_CODE (u32) 0x434E5546
|
||||
|
|
@ -730,13 +731,13 @@ T *CopyBytes(const T *aPtr, u64 aSize) {
|
|||
|
||||
template <typename... Args>
|
||||
void PrintNoNewLine(const char *aFmt, Args... aArgs) {
|
||||
printf(aFmt, aArgs...);
|
||||
log_to_terminal(aFmt, aArgs...);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Print(const char *aFmt, Args... aArgs) {
|
||||
printf(aFmt, aArgs...);
|
||||
log_to_terminal(aFmt, aArgs...);
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
|
@ -750,7 +751,7 @@ void PrintConsole(enum ConsoleMessageLevel level, const char *aFmt, Args... aArg
|
|||
|
||||
template <typename... Args>
|
||||
void PrintError(const char *aFmt, Args... aArgs) {
|
||||
printf(aFmt, aArgs...);
|
||||
log_to_terminal(aFmt, aArgs...);
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
PrintConsole(CONSOLE_MESSAGE_ERROR, aFmt, aArgs...);
|
||||
|
|
|
|||
|
|
@ -1136,6 +1136,7 @@
|
|||
<br />
|
||||
|
||||
## [djui_console.h](#djui_console.h)
|
||||
- MAX_CONSOLE_INPUT_LENGTH
|
||||
|
||||
### [enum ConsoleMessageLevel](#ConsoleMessageLevel)
|
||||
| Identifier | Value |
|
||||
|
|
|
|||
|
|
@ -9,36 +9,36 @@ function on_stream_play(msg)
|
|||
if(msg == "load") then
|
||||
audioStream = audio_stream_load("music.mp3")
|
||||
audio_stream_set_looping(audioStream, true)
|
||||
djui_chat_message_create("audio audioStream:" .. tostring(audioStream));
|
||||
command_message_create("audio audioStream:" .. tostring(audioStream));
|
||||
end
|
||||
|
||||
if(msg == "play") then
|
||||
audio_stream_play(audioStream, true, 1);
|
||||
djui_chat_message_create("playing audio");
|
||||
command_message_create("playing audio");
|
||||
end
|
||||
|
||||
if(msg == "resume") then
|
||||
audio_stream_play(audioStream, false, 1);
|
||||
djui_chat_message_create("resuming audio");
|
||||
command_message_create("resuming audio");
|
||||
end
|
||||
|
||||
if(msg == "pause") then
|
||||
audio_stream_pause(audioStream);
|
||||
djui_chat_message_create("pausing audio");
|
||||
command_message_create("pausing audio");
|
||||
end
|
||||
|
||||
if(msg == "stop") then
|
||||
audio_stream_stop(audioStream);
|
||||
djui_chat_message_create("stopping audio");
|
||||
command_message_create("stopping audio");
|
||||
end
|
||||
|
||||
if(msg == "destroy") then
|
||||
audio_stream_destroy(audioStream);
|
||||
djui_chat_message_create("destroyed audio");
|
||||
command_message_create("destroyed audio");
|
||||
end
|
||||
|
||||
if(msg == "getpos") then
|
||||
djui_chat_message_create("pos: " .. tostring(audio_stream_get_position(audioStream)));
|
||||
command_message_create("pos: " .. tostring(audio_stream_get_position(audioStream)));
|
||||
end
|
||||
|
||||
return true;
|
||||
|
|
@ -48,7 +48,7 @@ function on_sample_play(msg)
|
|||
if(msg == "load") then
|
||||
audioSample = audio_sample_load("sample.mp3");
|
||||
|
||||
djui_chat_message_create("audio audioStream:" .. tostring(audioSample));
|
||||
command_message_create("audio audioStream:" .. tostring(audioSample));
|
||||
|
||||
return true;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ function send_example_1(byte_param, short_param, long_param, float_param, double
|
|||
|
||||
network_send_bytestring(true, bytestring)
|
||||
|
||||
djui_chat_message_create('Sent bytestring packet example 1:')
|
||||
djui_chat_message_create(' byte_param: ' .. byte_param)
|
||||
djui_chat_message_create(' short_param: ' .. short_param)
|
||||
djui_chat_message_create(' long_param: ' .. long_param)
|
||||
djui_chat_message_create(' float_param: ' .. float_param)
|
||||
djui_chat_message_create(' double_param: ' .. double_param)
|
||||
command_message_create('Sent bytestring packet example 1:')
|
||||
command_message_create(' byte_param: ' .. byte_param)
|
||||
command_message_create(' short_param: ' .. short_param)
|
||||
command_message_create(' long_param: ' .. long_param)
|
||||
command_message_create(' float_param: ' .. float_param)
|
||||
command_message_create(' double_param: ' .. double_param)
|
||||
end
|
||||
|
||||
function on_packet_bytestring_receive_example_1(bytestring)
|
||||
|
|
@ -55,11 +55,17 @@ function on_packet_bytestring_receive_example_1(bytestring)
|
|||
---------------------------------------
|
||||
|
||||
djui_chat_message_create('Received bytestring packet example 1:')
|
||||
log_to_console('Received bytestring packet example 1:')
|
||||
djui_chat_message_create(' byte_param: ' .. byte_param)
|
||||
log_to_console(' byte_param: ' .. byte_param)
|
||||
djui_chat_message_create(' short_param: ' .. short_param)
|
||||
log_to_console(' short_param: ' .. short_param)
|
||||
djui_chat_message_create(' long_param: ' .. long_param)
|
||||
log_to_console(' long_param: ' .. long_param)
|
||||
djui_chat_message_create(' float_param: ' .. float_param)
|
||||
log_to_console(' float_param: ' .. float_param)
|
||||
djui_chat_message_create(' double_param: ' .. double_param)
|
||||
log_to_console(' double_param: ' .. double_param)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------------------
|
||||
|
|
@ -76,9 +82,9 @@ function send_example_2(long_param, string_param)
|
|||
|
||||
network_send_bytestring(true, bytestring)
|
||||
|
||||
djui_chat_message_create('Sent bytestring packet example 2:')
|
||||
djui_chat_message_create(' byte_param: ' .. long_param)
|
||||
djui_chat_message_create(' string_param: ' .. string_param)
|
||||
command_message_create('Sent bytestring packet example 2:')
|
||||
command_message_create(' byte_param: ' .. long_param)
|
||||
command_message_create(' string_param: ' .. string_param)
|
||||
end
|
||||
|
||||
function on_packet_bytestring_receive_example_2(bytestring)
|
||||
|
|
@ -98,8 +104,11 @@ function on_packet_bytestring_receive_example_2(bytestring)
|
|||
---------------------------------------
|
||||
|
||||
djui_chat_message_create('Received bytestring packet example 2:')
|
||||
log_to_console('Received bytestring packet example 2:')
|
||||
djui_chat_message_create(' long_param: ' .. long_param)
|
||||
log_to_console(' long_param: ' .. long_param)
|
||||
djui_chat_message_create(' string_param: ' .. string_param)
|
||||
log_to_console(' string_param: ' .. string_param)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2,18 +2,6 @@
|
|||
-- description: Run /matrix and a builtin texture name to replace with the digital rain
|
||||
-- deluxe: true
|
||||
|
||||
if SM64COOPDX_VERSION == nil then
|
||||
local first = false
|
||||
hook_event(HOOK_ON_LEVEL_INIT, function()
|
||||
if not first then
|
||||
first = true
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gMarioStates[0].marioObj.header.gfx.cameraToObject)
|
||||
djui_chat_message_create("\\#ff7f7f\\Matrix Code is not supported with sm64ex-coop\nas it uses sm64coopdx exclusive Lua functionality.\n\\#dcdcdc\\To use this mod, try out sm64coopdx at\n\\#7f7fff\\https://sm64coopdx.com")
|
||||
end
|
||||
end)
|
||||
return
|
||||
end
|
||||
|
||||
local sMatrixFrames = {}
|
||||
for i = 0, 10 do
|
||||
sMatrixFrames[i] = get_texture_info("matrix_" .. i)
|
||||
|
|
|
|||
|
|
@ -3,24 +3,24 @@
|
|||
|
||||
local function on_get_command(msg)
|
||||
if not network_is_server() then
|
||||
djui_chat_message_create("You need to be the host!")
|
||||
command_message_create("You need to be the host!", CONSOLE_MESSAGE_ERROR)
|
||||
return true
|
||||
end
|
||||
|
||||
djui_chat_message_create(tostring(get_water_level(0)))
|
||||
djui_chat_message_create(tostring(get_water_level(1)))
|
||||
command_message_create(tostring(get_water_level(0)))
|
||||
command_message_create(tostring(get_water_level(1)))
|
||||
return true
|
||||
end
|
||||
|
||||
local function on_set_command(msg)
|
||||
if not network_is_server() then
|
||||
djui_chat_message_create("You need to be the host!")
|
||||
command_message_create("You need to be the host!", CONSOLE_MESSAGE_ERROR)
|
||||
return true
|
||||
end
|
||||
|
||||
local num = tonumber(msg)
|
||||
if not num then
|
||||
djui_chat_message_create("Not a number!")
|
||||
command_message_create("Not a number!", CONSOLE_MESSAGE_ERROR)
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2661,6 +2661,33 @@ Updates Mario's current animation offset. This adjusts Mario's position based on
|
|||
|
||||
<br />
|
||||
|
||||
---
|
||||
# functions from commands.h
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
## [command_message_create](#command_message_create)
|
||||
|
||||
### Lua Example
|
||||
`command_message_create(message, level)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| message | `string` |
|
||||
| level | [enum ConsoleMessageLevel](constants.md#enum-ConsoleMessageLevel) |
|
||||
|
||||
### Returns
|
||||
- None
|
||||
|
||||
### C Prototype
|
||||
`void command_message_create(const char* message, OPTIONAL enum ConsoleMessageLevel level);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
# functions from djui_chat_message.h
|
||||
|
||||
|
|
|
|||
|
|
@ -740,6 +740,11 @@
|
|||
|
||||
<br />
|
||||
|
||||
- commands.h
|
||||
- [command_message_create](functions-3.md#command_message_create)
|
||||
|
||||
<br />
|
||||
|
||||
- djui_chat_message.h
|
||||
- [djui_chat_message_create](functions-3.md#djui_chat_message_create)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Hooks are a way for SM64 to trigger Lua code, whereas the functions listed in [f
|
|||
# Supported Hooks
|
||||
- [hook_behavior](#hook_behavior)
|
||||
- [hook_chat_command](#hook_chat_command)
|
||||
- [hook_console_command](#hook_console_command)
|
||||
- [hook_event](#hook_event)
|
||||
- [hook_mario_action](#hook_mario_action)
|
||||
- [hook_on_sync_table_change](#hook_on_sync_table_change)
|
||||
|
|
@ -54,7 +55,7 @@ id_bhvExample = hook_behavior(nil, OBJ_LIST_DEFAULT, true, bhv_example_init, bhv
|
|||
<br />
|
||||
|
||||
## [hook_chat_command](#hook_chat_command)
|
||||
`hook_chat_command()` allows Lua mods to react and respond to chat commands. Chat commands start with the `/` character. The function the mod passes to the hook should return `true` when the command was valid and `false` otherwise.
|
||||
`hook_chat_command()` allows Lua mods to react and respond to chat commands. Chat commands start with the `/` character. The function the mod passes to the hook should return `true` when the command was valid and `false` otherwise. Use `command_message_create` to show any message to the user. Chat commands appear in the chat, console, and terminal.
|
||||
|
||||
### Parameters
|
||||
|
||||
|
|
@ -69,10 +70,10 @@ id_bhvExample = hook_behavior(nil, OBJ_LIST_DEFAULT, true, bhv_example_init, bhv
|
|||
```lua
|
||||
function on_test_command(msg)
|
||||
if msg == "on" then
|
||||
djui_chat_message_create("Test: enabled")
|
||||
command_message_create("Test: enabled")
|
||||
return true
|
||||
elseif msg == "off" then
|
||||
djui_chat_message_create("Test: disabled")
|
||||
command_message_create("Test: disabled")
|
||||
return true
|
||||
end
|
||||
return false
|
||||
|
|
@ -85,6 +86,38 @@ hook_chat_command("test", "[on|off] turn test on or off", on_hide_and_seek_comma
|
|||
|
||||
<br />
|
||||
|
||||
## [hook_console_command](#hook_console_command)
|
||||
`hook_console_command()` allows Lua mods to react and respond to console commands. The function the mod passes to the hook should return `true` when the command was valid and `false` otherwise. You should use `command_message_create` to show any messages to the user. Console messages only appear in the console and terminal.
|
||||
|
||||
### Parameters
|
||||
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| command | `string` |
|
||||
| description | `string` |
|
||||
| func | `Lua Function` (`string` message) -> `bool` |
|
||||
|
||||
### Lua Example
|
||||
|
||||
```lua
|
||||
function on_test_command(msg)
|
||||
if msg == "on" then
|
||||
command_message_create("Test: enabled")
|
||||
return true
|
||||
elseif msg == "off" then
|
||||
command_message_create("Test: disabled")
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
hook_console_command("test", "[on|off] turn test on or off", on_test_command)
|
||||
```
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [hook_event](#hook_event)
|
||||
|
||||
The lua functions sent to `hook_event()` will be automatically called by SM64 when certain events occur.
|
||||
|
|
@ -143,7 +176,7 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh
|
|||
| HOOK_ON_GEO_PROCESS | Called when a GeoLayout is processed **Note:** You must set the `hookProcess` field of the graph node to a non-zero value | [GraphNode](../structs.md#GraphNode) graphNode, `integer` matStackIndex |
|
||||
| HOOK_BEFORE_GEO_PROCESS | Called before a GeoLayout is processed **Note:** You must set the `hookProcess` field of the graph node to a non-zero value | [GraphNode](../structs.md#GraphNode) graphNode, `integer` matStackIndex |
|
||||
| HOOK_ON_GEO_PROCESS_CHILDREN | Called when the children of a GeoLayout node is processed **Note:** You must set the `hookProcess` field of the parent graph node to a non-zero value | [GraphNode](../structs.md#GraphNode) graphNode, `integer` matStackIndex |
|
||||
| HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS | Called before running Mario's geometry input logic, return `false` to not run it. | [MarioState](../structs.md) m |
|
||||
| HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS | Called before running Mario's geometry input logic, return `false` to not run it. | [MarioState](../structs.md) m |
|
||||
| HOOK_ON_INTERACTIONS | Called when the Mario interactions are processed | [MarioState](../structs.md#MarioState) mario |
|
||||
| HOOK_ALLOW_FORCE_WATER_ACTION | Called when executing a non-water action while under the water's surface, or vice versa. Return `false` to prevent the player from being forced out of the action at the water's surface | [MarioState](../structs.md#MarioState) mario, `boolean` isInWaterAction |
|
||||
| HOOK_BEFORE_WARP | Called before the local player warps. Return a table with `destLevel`, `destArea`, `destWarpNode`, to override the warp | `integer` destLevel, `integer` destArea, `integer` destWarpNode, `integer` arg |
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ Save file locations:
|
|||
<br />
|
||||
|
||||
## Tips
|
||||
- When developing Lua mods, run the game from a console. Lua errors and logs will appear there, but only if the game is launched with the `--console` launch parameter.
|
||||
- When developing Lua mods, open the console with `~` or `F1` to see Lua errors and warnings.
|
||||
- When a function requests a time parameter, it is almost if not always in frames.
|
||||
- You can use the `print()` command when debugging. Your logs will show up in the console.
|
||||
- You can use the `print()` command when debugging. Your logs will show up in the console and terminal.
|
||||
- You can create a folder within the mods folder containing multiple lua scripts as long as one script is called `main.lua`. Dynos actors can be placed inside this mod folder under `<your mod folder>/actors/`.
|
||||
<br />
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ Save file locations:
|
|||
- [Structs](structs.md)
|
||||
|
||||
### Guides
|
||||
- [Setting up Visual Studio Code](guides/vs-code-setup.md)
|
||||
- [Setting up Visual Studio Code](guides/vs-code-setup.md)
|
||||
- [Hooks](guides/hooks.md)
|
||||
- [gMarioStates](guides/mario-state.md)
|
||||
- [Behavior Object Lists](guides/object-lists.md)
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ function on_arena_player_death(victimGlobalId, attackerGlobalId)
|
|||
if sAttacker.team ~= 0 then
|
||||
local teamScore = calculate_team_score(sAttacker.team)
|
||||
if teamScore >= gGameModes[gGlobalSyncTable.gameMode].scoreCap then
|
||||
round_end()
|
||||
round_end()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -472,7 +472,7 @@ function on_gamemode_command(msg)
|
|||
end
|
||||
|
||||
if msg == 'random' then
|
||||
djui_chat_message_create("[Arena] Setting to random gamemode.")
|
||||
command_message_create("[Arena] Setting to random gamemode.")
|
||||
sRandomizeMode = true
|
||||
round_end()
|
||||
sWaitTimer = 1
|
||||
|
|
@ -481,7 +481,7 @@ function on_gamemode_command(msg)
|
|||
end
|
||||
|
||||
if setMode ~= nil then
|
||||
djui_chat_message_create("[Arena] Setting game mode.")
|
||||
command_message_create("[Arena] Setting game mode.")
|
||||
gGlobalSyncTable.gameMode = setMode
|
||||
sRandomizeMode = false
|
||||
round_end()
|
||||
|
|
@ -490,7 +490,7 @@ function on_gamemode_command(msg)
|
|||
return true
|
||||
end
|
||||
|
||||
djui_chat_message_create("/arena \\#00ffff\\gamemode\\#ffff00\\ " .. string.format("[%s|random]\\#dcdcdc\\ sets gamemode", sGameModeShortTimes))
|
||||
command_message_create("/arena \\#00ffff\\gamemode\\#ffff00\\ " .. string.format("[%s|random]\\#dcdcdc\\ sets gamemode", sGameModeShortTimes))
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
@ -512,21 +512,21 @@ function on_level_command(msg)
|
|||
return true
|
||||
end
|
||||
|
||||
djui_chat_message_create("/arena \\#00ffff\\level\\#ffff00\\ " .. string.format("[%s]\\#dcdcdc\\ sets level", get_level_choices()))
|
||||
command_message_create("/arena \\#00ffff\\level\\#ffff00\\ " .. string.format("[%s]\\#dcdcdc\\ sets level", get_level_choices()))
|
||||
return true
|
||||
end
|
||||
|
||||
function on_jump_leniency_command(msg)
|
||||
local num = tonumber(msg)
|
||||
if not network_is_server and not network_is_moderator() then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Arena] You need to be a moderator to use this command.")
|
||||
command_message_create("\\#ffa0a0\\[Arena] You need to be a moderator to use this command.")
|
||||
return true
|
||||
elseif num == nil then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Arena] Invalid number!")
|
||||
command_message_create("\\#ffa0a0\\[Arena] Invalid number!")
|
||||
return true
|
||||
else
|
||||
gGlobalSyncTable.jumpLeniency = num
|
||||
djui_chat_message_create("[Arena] The number of jump leniency frames has been set to " .. num)
|
||||
command_message_create("[Arena] The number of jump leniency frames has been set to " .. num)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
|
@ -545,7 +545,7 @@ local function on_arena_command(msg)
|
|||
return on_jump_leniency_command(args[2] or "")
|
||||
end
|
||||
|
||||
djui_chat_message_create("/arena \\#00ffff\\[gamemode|level|jump-leniency]")
|
||||
command_message_create("/arena \\#00ffff\\[gamemode|level|jump-leniency]")
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ local function update_character_render_table()
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if #characterTableRender > 0 then
|
||||
-- Get icons for category based on name similarity
|
||||
if category.icon1 == nil or category.icon2 == nil then
|
||||
|
|
@ -902,7 +902,7 @@ local worldColor = {
|
|||
ambient = {r = 255, g = 255, b = 255}
|
||||
}
|
||||
local menuOffsetX = 0
|
||||
local menuOffsetY = 0
|
||||
local menuOffsetY = 0
|
||||
local camScale = 1
|
||||
local prevMusicToggle = 1
|
||||
local prevVisualToggle = 1
|
||||
|
|
@ -919,7 +919,7 @@ local function mario_update(m)
|
|||
set_all_models()
|
||||
queueStorageFailsafe = false
|
||||
end
|
||||
|
||||
|
||||
local np = gNetworkPlayers[m.playerIndex]
|
||||
local p = gCSPlayers[m.playerIndex]
|
||||
|
||||
|
|
@ -952,7 +952,7 @@ local function mario_update(m)
|
|||
end
|
||||
end
|
||||
|
||||
if djui_hud_is_pause_menu_created() then
|
||||
if djui_hud_is_pause_menu_created() then
|
||||
if prevBaseCharFrame ~= np.modelIndex then
|
||||
force_set_character(np.modelIndex)
|
||||
p.presetPalette = 0
|
||||
|
|
@ -978,7 +978,7 @@ local function mario_update(m)
|
|||
local charTable = characterTable[currChar]
|
||||
p.saveName = charTable.saveName
|
||||
p.currAlt = charTable.currAlt
|
||||
|
||||
|
||||
p.modelId = charTable[charTable.currAlt].model
|
||||
if charTable[charTable.currAlt].baseChar ~= nil then
|
||||
p.baseChar = charTable[charTable.currAlt].baseChar
|
||||
|
|
@ -1316,9 +1316,9 @@ function set_model(o, model)
|
|||
if o.oOriginalModel == 0 then
|
||||
o.oOriginalModel = obj_get_model_id_extended(o)
|
||||
end
|
||||
|
||||
|
||||
local model = run_func_or_get_var(currReplace, o, o.oOriginalModel)
|
||||
|
||||
|
||||
if model ~= nil and visualToggle then
|
||||
o.oModelHasBeenReplaced = 1
|
||||
if obj_has_model_extended(o, model) == 0 then
|
||||
|
|
@ -1601,7 +1601,7 @@ local function on_hud_render()
|
|||
djui_hud_set_color(charColor.r*0.5 + 127, charColor.g*0.5 + 127, charColor.b*0.5 + 127, math.min(paletteTrans, 255))
|
||||
djui_hud_print_text(paletteName, x, y, 0.5)
|
||||
end
|
||||
|
||||
|
||||
-- Render Background Wall
|
||||
local wallWidth = TEX_WALL_LEFT.width
|
||||
local wallHeight = TEX_WALL_LEFT.height
|
||||
|
|
@ -1615,11 +1615,11 @@ local function on_hud_render()
|
|||
djui_hud_render_texture_auto_interpolated("wall-l", TEX_WALL_LEFT, x, y, wallScale, wallScale)
|
||||
djui_hud_set_color(playerPants.r, playerPants.g, playerPants.b, 255)
|
||||
djui_hud_render_texture_auto_interpolated("wall-r", TEX_WALL_RIGHT, x, y, wallScale, wallScale)
|
||||
|
||||
|
||||
-- Render Graffiti
|
||||
local graffiti = characterGraffiti[currChar] or TEX_GRAFFITI_DEFAULT
|
||||
local graffitiWidthScale = 120/graffiti.width
|
||||
local graffitiHeightScale = 120/graffiti.width
|
||||
local graffitiWidthScale = 120/graffiti.width
|
||||
local graffitiHeightScale = 120/graffiti.width
|
||||
djui_hud_set_color(255, 255, 255, 150)
|
||||
djui_hud_render_texture_auto_interpolated("graffiti", graffiti, wallMiddle - graffiti.width*0.5*graffitiWidthScale - menuOffsetX, height*0.5 - graffiti.height*0.5*graffitiHeightScale - menuOffsetY, graffitiWidthScale, graffitiHeightScale)
|
||||
|
||||
|
|
@ -1638,7 +1638,7 @@ local function on_hud_render()
|
|||
local scale = 0.35
|
||||
local textScale = scale*1.5
|
||||
local buttonSpacing = 32
|
||||
|
||||
|
||||
if not gridMenu then
|
||||
-- Render Character List
|
||||
gridYOffset = lerp(gridYOffset, currCharRender*buttonSpacing, 0.1)
|
||||
|
|
@ -1666,7 +1666,7 @@ local function on_hud_render()
|
|||
-- Name Screen
|
||||
djui_hud_set_color(charColor.r*0.5, charColor.g*0.5, charColor.b*0.5, 255)
|
||||
djui_hud_print_text(charName, x + 112*scale + segments*16*scale*0.5 - charNameLength*textScale*0.5, y + 32*scale, textScale)
|
||||
|
||||
|
||||
-- Bottom Info
|
||||
djui_hud_render_rect(x + 112*scale, y + 84*scale, segments*16*scale, scale)
|
||||
djui_hud_print_text(channel, x + 112*scale, y + 85*scale, 0.3*scale)
|
||||
|
|
@ -1907,7 +1907,7 @@ local function on_hud_render()
|
|||
djui_hud_print_text(TEXT_VERSION, 2, height - 7, 0.4)
|
||||
local currMenu = gridMenu and MENU_BINDS_GRID or MENU_BINDS_DEFAULT
|
||||
if options == OPTIONS_MAIN then
|
||||
currMenu = MENU_BINDS_OPTIONS
|
||||
currMenu = MENU_BINDS_OPTIONS
|
||||
elseif options == OPTIONS_CREDITS then
|
||||
currMenu = MENU_BINDS_GRID
|
||||
end
|
||||
|
|
@ -2091,7 +2091,7 @@ local function before_mario_update(m)
|
|||
until update_character_render_table()
|
||||
gearRotationTarget = gearRotationTarget + 0x10000/#characterCategories
|
||||
categoryOpenTimer = 150
|
||||
|
||||
|
||||
play_sound(SOUND_MENU_CAMERA_TURN, cameraToObject)
|
||||
end
|
||||
)
|
||||
|
|
@ -2108,7 +2108,7 @@ local function before_mario_update(m)
|
|||
play_sound(SOUND_MENU_CAMERA_TURN, cameraToObject)
|
||||
end
|
||||
)
|
||||
|
||||
|
||||
if not gridMenu then
|
||||
-- List Controls
|
||||
run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL,
|
||||
|
|
@ -2150,7 +2150,7 @@ local function before_mario_update(m)
|
|||
end
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
else
|
||||
-- Grid Controls
|
||||
run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL,
|
||||
|
|
@ -2186,7 +2186,7 @@ local function before_mario_update(m)
|
|||
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||
end
|
||||
)
|
||||
|
||||
|
||||
-- Alt switcher
|
||||
if #characterTable[currChar] > 1 then
|
||||
run_func_with_condition_and_cooldown(FUNC_INDEX_ALT,
|
||||
|
|
@ -2392,14 +2392,14 @@ local function chat_command(msg)
|
|||
menu = not menu
|
||||
return true
|
||||
else
|
||||
djui_chat_message_create(TEXT_PAUSE_UNAVAILABLE)
|
||||
command_message_create(TEXT_PAUSE_UNAVAILABLE)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Help Prompt Check
|
||||
if msg == "?" or msg == "help" then
|
||||
djui_chat_message_create("Character Select's Avalible Commands:" ..
|
||||
command_message_create("Character Select's Avalible Commands:" ..
|
||||
"\n\\#ffff33\\/char-select help\\#ffffff\\ - Returns Avalible Commands" ..
|
||||
"\n\\#ffff33\\/char-select menu\\#ffffff\\ - Opens the Menu" ..
|
||||
"\n\\#ffff33\\/char-select [name/num]\\#ffffff\\ - Switches to Character" ..
|
||||
|
|
@ -2413,9 +2413,9 @@ local function chat_command(msg)
|
|||
return true
|
||||
end
|
||||
|
||||
-- Stop Character checks if API disallows it
|
||||
-- Stop Character checks if API disallows it
|
||||
if not menu_is_allowed() or charBeingSet then
|
||||
djui_chat_message_create("Character Cannot be Changed")
|
||||
command_message_create("Character Cannot be Changed")
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
@ -2426,7 +2426,7 @@ local function chat_command(msg)
|
|||
for a = 1, #characterTable[i] do
|
||||
if msg == string.lower(characterTable[i][a].name) or msg == saveName then
|
||||
force_set_character(i, msg ~= saveName and a or 1)
|
||||
djui_chat_message_create('Character set to "' .. characterTable[i][characterTable[i].currAlt].name .. '" Successfully!')
|
||||
command_message_create('Character set to "' .. characterTable[i][characterTable[i].currAlt].name .. '" Successfully!')
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
|
@ -2441,12 +2441,12 @@ local function chat_command(msg)
|
|||
altNum = altNum and altNum or 1
|
||||
if charNum > 0 and charNum <= #characterTable and characterTable[charNum].locked ~= LOCKED_TRUE then
|
||||
force_set_character(charNum, altNum)
|
||||
djui_chat_message_create('Character set to "' .. characterTable[charNum][altNum].name .. '" Successfully!')
|
||||
command_message_create('Character set to "' .. characterTable[charNum][altNum].name .. '" Successfully!')
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
djui_chat_message_create("Character Not Found")
|
||||
command_message_create("Character Not Found")
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -333,12 +333,12 @@ end
|
|||
local function on_set_command(msg)
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
if msg == "" then
|
||||
djui_chat_message_create("/time \\#00ffff\\set\\#ffff00\\ [TIME]\\#dcdcdc\\ to set the time")
|
||||
command_message_create("/time \\#00ffff\\set\\#ffff00\\ [TIME]\\#dcdcdc\\ to set the time")
|
||||
return
|
||||
end
|
||||
|
||||
|
|
@ -359,9 +359,9 @@ local function on_set_command(msg)
|
|||
local amount = tonumber(msg)
|
||||
if amount ~= nil then
|
||||
gGlobalSyncTable.time = amount * SECOND
|
||||
djui_chat_message_create("[Day Night Cycle] Time set to " .. math_floor(gGlobalSyncTable.time / SECOND))
|
||||
command_message_create("[Day Night Cycle] Time set to " .. math_floor(gGlobalSyncTable.time / SECOND))
|
||||
else
|
||||
djui_chat_message_create(string.format("\\#ffa0a0\\[Day Night Cycle] Could not set time to '%s'", msg))
|
||||
command_message_create(string.format("\\#ffa0a0\\[Day Night Cycle] Could not set time to '%s'", msg), CONSOLE_MESSAGE_ERROR)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -373,13 +373,13 @@ end
|
|||
local function on_add_command(msg)
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local amount = tonumber(msg)
|
||||
if amount == nil then
|
||||
djui_chat_message_create("/time \\#00ffff\\add\\#ffff00\\ [AMOUNT]\\#dcdcdc\\ to add to the time")
|
||||
command_message_create("/time \\#00ffff\\add\\#ffff00\\ [AMOUNT]\\#dcdcdc\\ to add to the time")
|
||||
return
|
||||
end
|
||||
local oldTime = gGlobalSyncTable.time
|
||||
|
|
@ -388,7 +388,7 @@ local function on_add_command(msg)
|
|||
|
||||
update_mod_menu_element_inputbox(modMenuTimeModifier, msg)
|
||||
|
||||
djui_chat_message_create("[Day Night Cycle] Time set to " .. math_floor(gGlobalSyncTable.time / SECOND))
|
||||
command_message_create("[Day Night Cycle] Time set to " .. math_floor(gGlobalSyncTable.time / SECOND))
|
||||
|
||||
save_time()
|
||||
end
|
||||
|
|
@ -397,13 +397,13 @@ end
|
|||
local function on_scale_command(msg)
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local scale = tonumber(msg)
|
||||
if scale == nil then
|
||||
djui_chat_message_create("/time \\#00ffff\\scale\\#ffff00\\ [SCALE]\\#dcdcdc\\ to scale the rate at which time passes")
|
||||
command_message_create("/time \\#00ffff\\scale\\#ffff00\\ [SCALE]\\#dcdcdc\\ to scale the rate at which time passes")
|
||||
return
|
||||
end
|
||||
gGlobalSyncTable.timeScale = scale
|
||||
|
|
@ -411,13 +411,13 @@ local function on_scale_command(msg)
|
|||
|
||||
update_mod_menu_element_slider(modMenuTimeScale, scale)
|
||||
|
||||
djui_chat_message_create("[Day Night Cycle] Time scale set to " .. scale)
|
||||
command_message_create("[Day Night Cycle] Time scale set to " .. scale)
|
||||
|
||||
save_time()
|
||||
end
|
||||
|
||||
local function on_query_command()
|
||||
djui_chat_message_create(string.format("[Day Night Cycle] Time is %d (%s), day %d", math_floor(gGlobalSyncTable.time / SECOND), get_time_string(gGlobalSyncTable.time), get_day_count()))
|
||||
command_message_create(string.format("[Day Night Cycle] Time is %d (%s), day %d", math_floor(gGlobalSyncTable.time / SECOND), get_time_string(gGlobalSyncTable.time), get_day_count()))
|
||||
end
|
||||
|
||||
local function on_24h_command()
|
||||
|
|
@ -430,11 +430,11 @@ end
|
|||
local function on_sync_command()
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
djui_chat_message_create("[Day Night Cycle] Attempting to sync in-game time with real life time...")
|
||||
command_message_create("[Day Night Cycle] Attempting to sync in-game time with real life time...")
|
||||
|
||||
local dateTime = get_date_and_time()
|
||||
gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * dateTime.hour) + (SECOND * dateTime.minute)
|
||||
|
|
@ -446,25 +446,25 @@ end
|
|||
local function on_sync_sun_command()
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
if dayNightCycleApi.lockSunHours then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] Changing sun hours has been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] Changing sun hours has been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
syncSun = not syncSun
|
||||
mod_storage_save_bool("sync_sun", syncSun)
|
||||
if syncSun then
|
||||
djui_chat_message_create("[Day Night Cycle] Syncing sunrise and sunset times to real life...")
|
||||
command_message_create("[Day Night Cycle] Syncing sunrise and sunset times to real life...")
|
||||
|
||||
local month = get_date_and_time().month + 1
|
||||
set_sun_hours(gSunriseTimes[month], gSunsetTimes[month])
|
||||
else
|
||||
djui_chat_message_create("[Day Night Cycle] Resetting sunrise and sunset times...")
|
||||
command_message_create("[Day Night Cycle] Resetting sunrise and sunset times...")
|
||||
|
||||
set_sun_hours(HOUR_SUNRISE_START_BASE, HOUR_SUNSET_START_BASE)
|
||||
end
|
||||
|
|
@ -475,13 +475,13 @@ end
|
|||
local function on_music_command()
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
playNightMusic = not playNightMusic
|
||||
mod_storage_save_bool("night_music", playNightMusic)
|
||||
djui_chat_message_create("[Day Night Cycle] Night music status: " .. on_or_off(playNightMusic))
|
||||
command_message_create("[Day Night Cycle] Night music status: " .. on_or_off(playNightMusic))
|
||||
|
||||
update_mod_menu_element_checkbox(modMenuMusic, playNightMusic)
|
||||
end
|
||||
|
|
@ -489,13 +489,13 @@ end
|
|||
local function on_display_time_command()
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
displayTime = not displayTime
|
||||
mod_storage_save_bool("display_time", displayTime)
|
||||
djui_chat_message_create("[Day Night Cycle] Display time status: " .. on_or_off(displayTime))
|
||||
command_message_create("[Day Night Cycle] Display time status: " .. on_or_off(displayTime))
|
||||
|
||||
update_mod_menu_element_checkbox(modMenuDisplayTime, displayTime)
|
||||
end
|
||||
|
|
@ -506,19 +506,19 @@ local function on_time_command(msg)
|
|||
|
||||
if args[1] == "set" then
|
||||
if not network_is_server() then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time set")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time set", CONSOLE_MESSAGE_ERROR)
|
||||
else
|
||||
on_set_command(args[2] or "")
|
||||
end
|
||||
elseif args[1] == "add" then
|
||||
if not network_is_server() then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time add")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time add", CONSOLE_MESSAGE_ERROR)
|
||||
else
|
||||
on_add_command(args[2] or "")
|
||||
end
|
||||
elseif args[1] == "scale" then
|
||||
if not network_is_server() then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time scale")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time scale", CONSOLE_MESSAGE_ERROR)
|
||||
else
|
||||
on_scale_command(args[2] or "")
|
||||
end
|
||||
|
|
@ -528,7 +528,7 @@ local function on_time_command(msg)
|
|||
on_24h_command()
|
||||
elseif args[1] == "sync" then
|
||||
if not network_is_server() then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time sync")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time sync", CONSOLE_MESSAGE_ERROR)
|
||||
else
|
||||
on_sync_command()
|
||||
end
|
||||
|
|
@ -539,13 +539,13 @@ local function on_time_command(msg)
|
|||
elseif args[1] == "display-time" then
|
||||
on_display_time_command()
|
||||
elseif args[1] ~= nil then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] Unrecognized command '" .. args[1] .. "'")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] Unrecognized command '" .. args[1] .. "'", CONSOLE_MESSAGE_ERROR)
|
||||
else
|
||||
if not network_is_server() then
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to enable or disable Day Night Cycle")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to enable or disable Day Night Cycle", CONSOLE_MESSAGE_ERROR)
|
||||
else
|
||||
gGlobalSyncTable.dncEnabled = not gGlobalSyncTable.dncEnabled
|
||||
djui_chat_message_create("[Day Night Cycle] Status: " .. on_or_off(gGlobalSyncTable.dncEnabled))
|
||||
command_message_create("[Day Night Cycle] Status: " .. on_or_off(gGlobalSyncTable.dncEnabled))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -586,7 +586,7 @@ end
|
|||
local function on_set_dnc_enabled(_, value)
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
|
|
@ -597,7 +597,7 @@ end
|
|||
local function on_set_time_scale(index, value)
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
|
|
@ -610,7 +610,7 @@ end
|
|||
local function on_set_time_modifier(_, value)
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
|
|
@ -621,7 +621,7 @@ end
|
|||
local function on_add_hour()
|
||||
if dayNightCycleApi.lockTime then
|
||||
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource)
|
||||
djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.")
|
||||
command_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.", CONSOLE_MESSAGE_ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -389,31 +389,31 @@ end
|
|||
|
||||
local function on_touch_tag_command()
|
||||
gGlobalSyncTable.touchTag = not gGlobalSyncTable.touchTag
|
||||
djui_chat_message_create("Touch tag: " .. on_or_off(gGlobalSyncTable.touchTag))
|
||||
command_message_create("Touch tag: " .. on_or_off(gGlobalSyncTable.touchTag))
|
||||
return true
|
||||
end
|
||||
|
||||
local function on_hider_cap_command()
|
||||
gGlobalSyncTable.hiderCaps = not gGlobalSyncTable.hiderCaps
|
||||
djui_chat_message_create("Hider Caps: " .. on_or_off(gGlobalSyncTable.hiderCaps))
|
||||
command_message_create("Hider Caps: " .. on_or_off(gGlobalSyncTable.hiderCaps))
|
||||
return true
|
||||
end
|
||||
|
||||
local function on_seeker_cap_command()
|
||||
gGlobalSyncTable.seekerCaps = not gGlobalSyncTable.seekerCaps
|
||||
djui_chat_message_create("Seeker Caps: " .. on_or_off(gGlobalSyncTable.seekerCaps))
|
||||
command_message_create("Seeker Caps: " .. on_or_off(gGlobalSyncTable.seekerCaps))
|
||||
return true
|
||||
end
|
||||
|
||||
local function on_koopa_shell_command()
|
||||
gGlobalSyncTable.banKoopaShell = not gGlobalSyncTable.banKoopaShell
|
||||
djui_chat_message_create("Koopa Shells: " .. on_or_off(not gGlobalSyncTable.banKoopaShell))
|
||||
command_message_create("Koopa Shells: " .. on_or_off(not gGlobalSyncTable.banKoopaShell))
|
||||
return true
|
||||
end
|
||||
|
||||
local function on_blj_command()
|
||||
gGlobalSyncTable.disableBLJ = not gGlobalSyncTable.disableBLJ
|
||||
djui_chat_message_create("BLJS: " .. on_or_off(not gGlobalSyncTable.disableBLJ))
|
||||
command_message_create("BLJS: " .. on_or_off(not gGlobalSyncTable.disableBLJ))
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ end
|
|||
local function on_swap_command()
|
||||
local np = gNetworkPlayers[0]
|
||||
if np.currAreaIndex == 1 then
|
||||
djui_chat_message_create("Swapping to Extreme Edition")
|
||||
command_message_create("Swapping to Extreme Edition")
|
||||
else
|
||||
djui_chat_message_create("Swapping to normal edition")
|
||||
command_message_create("Swapping to normal edition")
|
||||
end
|
||||
warp_to_level(np.currLevelNum, np.currAreaIndex ~ 3, np.currActNum)
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "pc/ini.h"
|
||||
#include "pc/debuglog.h"
|
||||
#include "pc/mods/mods.h"
|
||||
#include "pc/mods/mods_utils.h"
|
||||
#include "player_palette.h"
|
||||
|
|
@ -118,7 +119,7 @@ void player_palettes_read(const char* palettesPath, bool appendPalettes) {
|
|||
|
||||
if (!player_palette_init(palettesPath, path, appendPalettes)) {
|
||||
#ifdef DEVELOPMENT
|
||||
printf("Failed to load palette '%s.ini'\n", path);
|
||||
LOG_ERROR("Failed to load palette '%s.ini'\n", path);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
|
@ -140,7 +141,7 @@ void player_palettes_read(const char* palettesPath, bool appendPalettes) {
|
|||
gPresetPalettes[gPresetPaletteCount].palette = palette;
|
||||
gPresetPaletteCount++;
|
||||
#ifdef DEVELOPMENT
|
||||
printf("Loaded palette '%s.ini'\n", path);
|
||||
LOG_INFO("Loaded palette '%s.ini'\n", path);
|
||||
#endif
|
||||
if (gPresetPaletteCount >= MAX_PRESET_PALETTES) { break; }
|
||||
}
|
||||
|
|
@ -160,7 +161,7 @@ void player_palette_export(char* name) {
|
|||
snprintf(ppath, SYS_MAX_PATH, "%s/%s.ini", palettesPath, name);
|
||||
fs_sys_mkdir(palettesPath);
|
||||
|
||||
printf("Saving palette as '%s.ini'\n", name);
|
||||
LOG_INFO("Saving palette as '%s.ini'\n", name);
|
||||
FILE* file = fopen(ppath, "w");
|
||||
fprintf(file, "[PALETTE]\n\
|
||||
PANTS_R = %d\n\
|
||||
|
|
@ -224,7 +225,7 @@ bool player_palette_delete(const char* palettesPath, char* name, bool appendPale
|
|||
}
|
||||
|
||||
if (remove(ppath) == 0) {
|
||||
printf("Deleting palette '%s.ini'\n", name);
|
||||
LOG_INFO("Deleting palette '%s.ini'\n", name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,276 +0,0 @@
|
|||
#include "pc/network/network.h"
|
||||
#include "pc/network/socket/socket.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
#include "pc/djui/djui_language.h"
|
||||
#include "pc/djui/djui_chat_message.h"
|
||||
#include "chat_commands.h"
|
||||
#include "pc/network/ban_list.h"
|
||||
#include "pc/network/moderator_list.h"
|
||||
#include "pc/debuglog.h"
|
||||
#include "pc/lua/utils/smlua_level_utils.h"
|
||||
#include "pc/mods/mods_utils.h"
|
||||
#include "level_table.h"
|
||||
#ifdef DEVELOPMENT
|
||||
#include "pc/dev/chat.h"
|
||||
#endif
|
||||
|
||||
static enum ChatConfirmCommand sConfirming = CCC_NONE;
|
||||
static u8 sConfirmPlayerIndex = 0;
|
||||
|
||||
static struct NetworkPlayer* chat_get_network_player(const char* name) {
|
||||
// check for id
|
||||
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
||||
if (!gNetworkPlayers[i].connected) { continue; }
|
||||
char id[16] = { 0 };
|
||||
if (snprintf(id, 16, "%d", i) < 0) {
|
||||
// do nothing
|
||||
}
|
||||
if (strcmp(id, name) == 0) {
|
||||
return &gNetworkPlayers[i];
|
||||
}
|
||||
}
|
||||
|
||||
// check for name
|
||||
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
||||
if (!gNetworkPlayers[i].connected) { continue; }
|
||||
if (strcmp(gNetworkPlayers[i].name, name) == 0) {
|
||||
return &gNetworkPlayers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void chat_construct_player_message(struct NetworkPlayer* np, char* msg) {
|
||||
char built[256] = { 0 };
|
||||
snprintf(built, 256, "\\#fff982\\");
|
||||
|
||||
char player[128] = { 0 };
|
||||
snprintf(player, 128, "%s%s\\#fff982\\", network_get_player_text_color_string(np->localIndex), np->name);
|
||||
djui_language_replace(msg, &built[9], 256 - 9, '@', player);
|
||||
djui_chat_message_create(built);
|
||||
}
|
||||
|
||||
bool exec_chat_command(char* command) {
|
||||
struct NetworkPlayer* npl = &gNetworkPlayers[0];
|
||||
enum ChatConfirmCommand ccc = sConfirming;
|
||||
sConfirming = CCC_NONE;
|
||||
|
||||
if (ccc != CCC_NONE && strcmp("/confirm", command) == 0) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
|
||||
if (!np->connected) return true;
|
||||
if (gNetworkType == NT_SERVER || npl->moderator) {
|
||||
if (ccc == CCC_KICK) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, KICKING));
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
network_send_kick(np->localIndex, EKT_KICKED);
|
||||
network_player_disconnected(np->localIndex);
|
||||
} else {
|
||||
network_send_chat_command(np->globalIndex, CCC_KICK);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (gNetworkType == NT_SERVER || npl->moderator) {
|
||||
if (ccc == CCC_BAN) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, BANNING));
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
network_send_kick(np->localIndex, EKT_BANNED);
|
||||
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), false);
|
||||
network_player_disconnected(np->localIndex);
|
||||
} else {
|
||||
network_send_chat_command(np->globalIndex, CCC_BAN);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (gNetworkType == NT_SERVER && ccc == CCC_PERMBAN) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, PERM_BANNING));
|
||||
network_send_kick(np->localIndex, EKT_BANNED);
|
||||
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
|
||||
network_player_disconnected(np->localIndex);
|
||||
return true;
|
||||
}
|
||||
if (gNetworkType == NT_SERVER && ccc == CCC_MODERATOR) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, ADD_MODERATOR));
|
||||
np->moderator = true;
|
||||
network_send_moderator(np->localIndex);
|
||||
moderator_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp("/players", command) == 0) {
|
||||
char line[128] = { 0 };
|
||||
snprintf(line, 127, "\\#fff982\\%s:\n", DLANG(CHAT, PLAYERS));
|
||||
djui_chat_message_create(line);
|
||||
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
if (!np->connected) { continue; }
|
||||
if (gNetworkSystem == &gNetworkSystemSocket) {
|
||||
snprintf(line, 127, "\\#82f9ff\\%u\\#fff982\\ - %s%s\n", np->globalIndex, network_get_player_text_color_string(np->localIndex), np->name);
|
||||
} else {
|
||||
snprintf(line, 127, "\\#82f9ff\\%u\\#fff982\\ - \\#82f9ff\\%s\\#fff982\\ - %s%s\n", np->globalIndex, gNetworkSystem->get_id_str(np->localIndex), network_get_player_text_color_string(np->localIndex), np->name);
|
||||
}
|
||||
djui_chat_message_create(line);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp("/kick", command) == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/kick ")) {
|
||||
if (gNetworkType != NT_SERVER && !npl->moderator) {
|
||||
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(&command[6]);
|
||||
if (np == NULL) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, SELF_KICK));
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, KICK_CONFIRM));
|
||||
sConfirming = CCC_KICK;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp("/ban", command) == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/ban ")) {
|
||||
if (gNetworkType != NT_SERVER && !npl->moderator) {
|
||||
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(&command[5]);
|
||||
if (np == NULL) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, SELF_BAN));
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, BAN_CONFIRM));
|
||||
sConfirming = CCC_BAN;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp("/permban", command) == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/permban ")) {
|
||||
if (gNetworkType != NT_SERVER && !npl->moderator) {
|
||||
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(&command[9]);
|
||||
if (np == NULL) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, SELF_BAN));
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, PERM_BAN_CONFIRM));
|
||||
sConfirming = CCC_PERMBAN;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp("/moderator", command) == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/moderator ")) {
|
||||
if (gNetworkType != NT_SERVER) {
|
||||
djui_chat_message_create(DLANG(CHAT, SERVER_ONLY));
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(&command[11]);
|
||||
if (np == NULL) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, SELF_MOD));
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, MOD_CONFIRM));
|
||||
sConfirming = CCC_MODERATOR;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gServerSettings.nametags) {
|
||||
if (strcmp("/nametags", command) == 0) {
|
||||
djui_chat_message_create(DLANG(CHAT, NAMETAGS_MISSING_PARAMETERS));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/nametags ")) {
|
||||
char *option = &command[10];
|
||||
if (strcmp("show-tag", option) == 0) {
|
||||
gNametagsSettings.showSelfTag = !gNametagsSettings.showSelfTag;
|
||||
} else if (strcmp("show-health", option) == 0) {
|
||||
gNametagsSettings.showHealth = !gNametagsSettings.showHealth;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEVELOPMENT
|
||||
if (exec_dev_chat_command(command)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return smlua_call_chat_command_hook(command);
|
||||
}
|
||||
|
||||
void display_chat_commands(void) {
|
||||
djui_chat_message_create(DLANG(CHAT, PLAYERS_DESC));
|
||||
if (gNetworkType == NT_SERVER || gNetworkPlayers[0].moderator) {
|
||||
djui_chat_message_create(DLANG(CHAT, KICK_DESC));
|
||||
djui_chat_message_create(DLANG(CHAT, BAN_DESC));
|
||||
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_chat_message_create(DLANG(CHAT, PERM_BAN_DESC));
|
||||
djui_chat_message_create(DLANG(CHAT, MOD_DESC));
|
||||
}
|
||||
}
|
||||
if (gServerSettings.nametags) {
|
||||
djui_chat_message_create(DLANG(CHAT, NAMETAGS_DESC));
|
||||
}
|
||||
#ifdef DEVELOPMENT
|
||||
dev_display_chat_commands();
|
||||
#endif
|
||||
if (sConfirming != CCC_NONE) { djui_chat_message_create("/confirm"); }
|
||||
smlua_display_chat_commands();
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef CHAT_COMMANDS_H
|
||||
#define CHAT_COMMANDS_H
|
||||
|
||||
bool exec_chat_command(char* command);
|
||||
void display_chat_commands(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include "pc_main.h"
|
||||
#include "platform.h"
|
||||
#include "macros.h"
|
||||
#include "debuglog.h"
|
||||
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -13,28 +14,28 @@
|
|||
struct CLIOptions gCLIOpts;
|
||||
|
||||
static void print_help(void) {
|
||||
printf("sm64coopdx\n");
|
||||
log_to_terminal("sm64coopdx\n");
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
printf("--console Enables the Windows console.\n");
|
||||
log_to_terminal("--console Enables the Windows console.\n");
|
||||
#endif
|
||||
printf("--savepath SAVEPATH Overrides the default save/config path ('!' expands to executable path).\n");
|
||||
printf("--configfile CONFIGNAME Saves the configuration file as CONFIGNAME.\n");
|
||||
printf("--hide-loading-screen Hides the loading screen before the menu boots up.\n");
|
||||
printf("--fullscreen Starts the game in full screen mode.\n");
|
||||
printf("--windowed Starts the game in windowed mode.\n");
|
||||
printf("--width WIDTH Sets the window width.\n");
|
||||
printf("--height HEIGHT Sets the window height.\n");
|
||||
printf("--skip-intro Skips the Peach and Lakitu intros when on a zero star save.\n");
|
||||
printf("--server PORT Starts the game and creates a new server on PORT.\n");
|
||||
printf("--client IP PORT Starts the game and joins an existing server.\n");
|
||||
printf("--coopnet PASSWORD Starts the game and creates a new CoopNet server.\n");
|
||||
printf("--playername PLAYERNAME Starts the game with a specific playername.\n");
|
||||
printf("--playercount PLAYERCOUNT Starts the game with a specific player count limit.\n");
|
||||
printf("--skip-update-check Skips the update check when loading the game.\n");
|
||||
printf("--no-discord Disables discord integration.\n");
|
||||
printf("--disable-mods Disables all mods that are already enabled.\n");
|
||||
printf("--enable-mod MODNAME Enables a mod.\n");
|
||||
printf("--headless Enable Headless mode.");
|
||||
log_to_terminal("--savepath SAVEPATH Overrides the default save/config path ('!' expands to executable path).\n");
|
||||
log_to_terminal("--configfile CONFIGNAME Saves the configuration file as CONFIGNAME.\n");
|
||||
log_to_terminal("--hide-loading-screen Hides the loading screen before the menu boots up.\n");
|
||||
log_to_terminal("--fullscreen Starts the game in full screen mode.\n");
|
||||
log_to_terminal("--windowed Starts the game in windowed mode.\n");
|
||||
log_to_terminal("--width WIDTH Sets the window width.\n");
|
||||
log_to_terminal("--height HEIGHT Sets the window height.\n");
|
||||
log_to_terminal("--skip-intro Skips the Peach and Lakitu intros when on a zero star save.\n");
|
||||
log_to_terminal("--server PORT Starts the game and creates a new server on PORT.\n");
|
||||
log_to_terminal("--client IP PORT Starts the game and joins an existing server.\n");
|
||||
log_to_terminal("--coopnet PASSWORD Starts the game and creates a new CoopNet server.\n");
|
||||
log_to_terminal("--playername PLAYERNAME Starts the game with a specific playername.\n");
|
||||
log_to_terminal("--playercount PLAYERCOUNT Starts the game with a specific player count limit.\n");
|
||||
log_to_terminal("--skip-update-check Skips the update check when loading the game.\n");
|
||||
log_to_terminal("--no-discord Disables discord integration.\n");
|
||||
log_to_terminal("--disable-mods Disables all mods that are already enabled.\n");
|
||||
log_to_terminal("--enable-mod MODNAME Enables a mod.\n");
|
||||
log_to_terminal("--headless Enable Headless mode.");
|
||||
}
|
||||
|
||||
static inline int arg_string(const char *name, const char *value, char *target, int maxLength) {
|
||||
|
|
|
|||
483
src/pc/commands.c
Normal file
483
src/pc/commands.c
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
#include "pc/network/network.h"
|
||||
#include "pc/network/socket/socket.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
#include "pc/djui/djui_language.h"
|
||||
#include "pc/djui/djui_chat_message.h"
|
||||
#include "pc/djui/djui_console.h"
|
||||
#include "commands.h"
|
||||
#include "pc/network/ban_list.h"
|
||||
#include "pc/network/moderator_list.h"
|
||||
#include "pc/debuglog.h"
|
||||
#include "pc/lua/utils/smlua_level_utils.h"
|
||||
#include "pc/mods/mods_utils.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "level_table.h"
|
||||
#ifdef DEVELOPMENT
|
||||
#include "pc/dev/chat.h"
|
||||
#endif
|
||||
|
||||
static bool command_help(UNUSED const char* message);
|
||||
static bool command_players(UNUSED const char* message);
|
||||
static bool command_kick(const char* message);
|
||||
static bool command_ban(const char* message);
|
||||
static bool command_permaban(const char* message);
|
||||
static bool command_mod(const char* message);
|
||||
static bool command_confirm(UNUSED const char* message);
|
||||
static bool command_nametags(const char* message);
|
||||
static bool command_clear(UNUSED const char* message);
|
||||
static bool command_quit(UNUSED const char* message);
|
||||
static bool command_host(UNUSED const char* message);
|
||||
static bool command_rehost(UNUSED const char* message);
|
||||
static bool command_stop_hosting(UNUSED const char* message);
|
||||
static bool command_disconnect(UNUSED const char* message);
|
||||
|
||||
static struct Command sCommands[] = {
|
||||
{
|
||||
.command = "players",
|
||||
.description = "PLAYERS_DESC",
|
||||
.action = command_players,
|
||||
.active = true,
|
||||
.isChatCommand = true
|
||||
},
|
||||
{
|
||||
.command = "kick",
|
||||
.description = "KICK_DESC",
|
||||
.action = command_kick,
|
||||
.active = true,
|
||||
.isChatCommand = true
|
||||
},
|
||||
{
|
||||
.command = "ban",
|
||||
.description = "BAN_DESC",
|
||||
.action = command_ban,
|
||||
.active = true,
|
||||
.isChatCommand = true
|
||||
},
|
||||
{
|
||||
.command = "permaban",
|
||||
.description = "PERM_BAN_DESC",
|
||||
.action = command_permaban,
|
||||
.active = true,
|
||||
.isChatCommand = true
|
||||
},
|
||||
{
|
||||
.command = "moderator",
|
||||
.description = "MOD_DESC",
|
||||
.action = command_mod,
|
||||
.active = true,
|
||||
.isChatCommand = true
|
||||
},
|
||||
{
|
||||
.command = "confirm",
|
||||
.description = "",
|
||||
.action = command_confirm,
|
||||
.active = false,
|
||||
.isChatCommand = true
|
||||
},
|
||||
{
|
||||
.command = "nametags",
|
||||
.description = "NAMETAGS_DESC",
|
||||
.action = command_nametags,
|
||||
.active = false,
|
||||
.isChatCommand = true
|
||||
},
|
||||
{
|
||||
.command = "clear",
|
||||
.description = "/clear - Clears the current console's text",
|
||||
.action = command_clear,
|
||||
.active = true,
|
||||
.isChatCommand = false
|
||||
},
|
||||
{
|
||||
.command = "quit",
|
||||
.description = "/quit - Quits the game",
|
||||
.action = command_quit,
|
||||
.active = true,
|
||||
.isChatCommand = false
|
||||
},
|
||||
{
|
||||
.command = "host",
|
||||
.description = "/host - Hosts a new game using your saved server settings and mod list",
|
||||
.action = command_host,
|
||||
.active = true,
|
||||
.isChatCommand = false
|
||||
},
|
||||
{
|
||||
.command = "rehost",
|
||||
.description = "/rehost - Rehosts a currently active game",
|
||||
.action = command_rehost,
|
||||
.active = false,
|
||||
.isChatCommand = false
|
||||
},
|
||||
{
|
||||
.command = "stop-hosting",
|
||||
.description = "/stop-hosting - Stop hosting a currently active game",
|
||||
.action = command_stop_hosting,
|
||||
.active = false,
|
||||
.isChatCommand = false
|
||||
},
|
||||
{
|
||||
.command = "disconnect",
|
||||
.description = "/disconnect - Disconnects from a currently active game",
|
||||
.action = command_disconnect,
|
||||
.active = false,
|
||||
.isChatCommand = false
|
||||
},
|
||||
};
|
||||
static unsigned int sCommandCount = sizeof(sCommands) / sizeof(struct Command);
|
||||
static enum ChatConfirmCommand sConfirming = CCC_NONE;
|
||||
static u8 sConfirmPlayerIndex = 0;
|
||||
|
||||
static struct NetworkPlayer* chat_get_network_player(const char* name) {
|
||||
// check for id
|
||||
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
||||
if (!gNetworkPlayers[i].connected) { continue; }
|
||||
char id[16] = { 0 };
|
||||
if (snprintf(id, 16, "%d", i) < 0) {
|
||||
// do nothing
|
||||
}
|
||||
if (strcmp(id, name) == 0) {
|
||||
return &gNetworkPlayers[i];
|
||||
}
|
||||
}
|
||||
|
||||
// check for name
|
||||
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
||||
if (!gNetworkPlayers[i].connected) { continue; }
|
||||
if (strcmp(gNetworkPlayers[i].name, name) == 0) {
|
||||
return &gNetworkPlayers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void chat_construct_player_message(struct NetworkPlayer* np, char* msg) {
|
||||
char built[256] = { 0 };
|
||||
snprintf(built, 256, "\\#fff982\\");
|
||||
|
||||
char player[128] = { 0 };
|
||||
snprintf(player, 128, "%s%s\\#fff982\\", network_get_player_text_color_string(np->localIndex), np->name);
|
||||
djui_language_replace(msg, &built[9], 256 - 9, '@', player);
|
||||
command_message_create(built, CONSOLE_MESSAGE_INFO);
|
||||
}
|
||||
|
||||
static bool command_help(UNUSED const char* message) {
|
||||
for (unsigned int i = 0; i < sCommandCount; i++) {
|
||||
if (!sCommands[i].active) continue;
|
||||
if (!sCommands[i].isChatCommand && gDjuiChatBoxFocus) continue;
|
||||
command_message_create(djui_language_get("CHAT", sCommands[i].description), CONSOLE_MESSAGE_INFO);
|
||||
}
|
||||
#ifdef DEVELOPMENT
|
||||
dev_display_chat_commands();
|
||||
#endif
|
||||
smlua_display_chat_commands(gDjuiConsoleFocus);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_players(UNUSED const char* message) {
|
||||
char line[128] = { 0 };
|
||||
snprintf(line, 127, "\\#fff982\\%s:\n", DLANG(CHAT, PLAYERS));
|
||||
command_message_create(line, CONSOLE_MESSAGE_INFO);
|
||||
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
if (!np->connected) { continue; }
|
||||
if (gNetworkSystem == &gNetworkSystemSocket) {
|
||||
snprintf(line, 127, "\\#82f9ff\\%u\\#fff982\\ - %s%s\n", np->globalIndex, network_get_player_text_color_string(np->localIndex), np->name);
|
||||
} else {
|
||||
snprintf(line, 127, "\\#82f9ff\\%u\\#fff982\\ - \\#82f9ff\\%s\\#fff982\\ - %s%s\n", np->globalIndex, gNetworkSystem->get_id_str(np->localIndex), network_get_player_text_color_string(np->localIndex), np->name);
|
||||
}
|
||||
command_message_create(line, CONSOLE_MESSAGE_INFO);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_kick(const char* message) {
|
||||
struct NetworkPlayer* npl = &gNetworkPlayers[0];
|
||||
if (gNetworkType != NT_SERVER && !npl->moderator) {
|
||||
command_message_create(DLANG(CHAT, NO_PERMS), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(message);
|
||||
if (np == NULL) {
|
||||
command_message_create(DLANG(CHAT, PLAYER_NOT_FOUND), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
command_message_create(DLANG(CHAT, SELF_KICK), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, KICK_CONFIRM));
|
||||
sConfirming = CCC_KICK;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
struct Command* confirmCommand = get_command("confirm");
|
||||
if (confirmCommand) confirmCommand->active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_ban(const char* message) {
|
||||
struct NetworkPlayer* npl = &gNetworkPlayers[0];
|
||||
if (gNetworkType != NT_SERVER && !npl->moderator) {
|
||||
command_message_create(DLANG(CHAT, NO_PERMS), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(message);
|
||||
if (np == NULL) {
|
||||
command_message_create(DLANG(CHAT, PLAYER_NOT_FOUND), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
command_message_create(DLANG(CHAT, SELF_BAN), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, BAN_CONFIRM));
|
||||
sConfirming = CCC_BAN;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
struct Command* confirmCommand = get_command("confirm");
|
||||
if (confirmCommand) confirmCommand->active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_permaban(const char* message) {
|
||||
struct NetworkPlayer* npl = &gNetworkPlayers[0];
|
||||
if (gNetworkType != NT_SERVER && !npl->moderator) {
|
||||
command_message_create(DLANG(CHAT, NO_PERMS), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(message);
|
||||
if (np == NULL) {
|
||||
command_message_create(DLANG(CHAT, PLAYER_NOT_FOUND), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
command_message_create(DLANG(CHAT, SELF_BAN), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, PERM_BAN_CONFIRM));
|
||||
sConfirming = CCC_PERMBAN;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
struct Command* confirmCommand = get_command("confirm");
|
||||
if (confirmCommand) confirmCommand->active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_mod(const char* message) {
|
||||
if (gNetworkType != NT_SERVER) {
|
||||
command_message_create(DLANG(CHAT, SERVER_ONLY), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NetworkPlayer* np = chat_get_network_player(message);
|
||||
if (np == NULL) {
|
||||
command_message_create(DLANG(CHAT, PLAYER_NOT_FOUND), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (np->localIndex == 0) {
|
||||
command_message_create(DLANG(CHAT, SELF_MOD), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
chat_construct_player_message(np, DLANG(CHAT, MOD_CONFIRM));
|
||||
sConfirming = CCC_MODERATOR;
|
||||
sConfirmPlayerIndex = np->localIndex;
|
||||
struct Command* confirmCommand = get_command("confirm");
|
||||
if (confirmCommand) confirmCommand->active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_confirm(UNUSED const char* message) {
|
||||
// deactivate command
|
||||
struct Command* confirmCommand = get_command("confirm");
|
||||
if (confirmCommand) confirmCommand->active = false;
|
||||
|
||||
enum ChatConfirmCommand ccc = sConfirming;
|
||||
sConfirming = CCC_NONE;
|
||||
|
||||
struct NetworkPlayer* npl = &gNetworkPlayers[0];
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
|
||||
if (!np->connected) return true;
|
||||
if (gNetworkType == NT_SERVER || npl->moderator) {
|
||||
if (ccc == CCC_KICK) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, KICKING));
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
network_send_kick(np->localIndex, EKT_KICKED);
|
||||
network_player_disconnected(np->localIndex);
|
||||
} else {
|
||||
network_send_chat_command(np->globalIndex, CCC_KICK);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (gNetworkType == NT_SERVER || npl->moderator) {
|
||||
if (ccc == CCC_BAN) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, BANNING));
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
network_send_kick(np->localIndex, EKT_BANNED);
|
||||
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), false);
|
||||
network_player_disconnected(np->localIndex);
|
||||
} else {
|
||||
network_send_chat_command(np->globalIndex, CCC_BAN);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (gNetworkType == NT_SERVER && ccc == CCC_PERMBAN) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, PERM_BANNING));
|
||||
network_send_kick(np->localIndex, EKT_BANNED);
|
||||
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
|
||||
network_player_disconnected(np->localIndex);
|
||||
return true;
|
||||
}
|
||||
if (gNetworkType == NT_SERVER && ccc == CCC_MODERATOR) {
|
||||
chat_construct_player_message(np, DLANG(CHAT, ADD_MODERATOR));
|
||||
np->moderator = true;
|
||||
network_send_moderator(np->localIndex);
|
||||
moderator_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool command_nametags(const char* message) {
|
||||
if (strcmp("show-tag", message) == 0) {
|
||||
gNametagsSettings.showSelfTag = !gNametagsSettings.showSelfTag;
|
||||
} else if (strcmp("show-health", message) == 0) {
|
||||
gNametagsSettings.showHealth = !gNametagsSettings.showHealth;
|
||||
}
|
||||
command_message_create(DLANG(CHAT, NAMETAGS_MISSING_PARAMETERS), CONSOLE_MESSAGE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_clear(UNUSED const char* message) {
|
||||
djui_console_clear();
|
||||
terminal_clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_quit(UNUSED const char* message) {
|
||||
game_exit();
|
||||
return true;
|
||||
}
|
||||
|
||||
extern void djui_panel_do_host(bool reconnecting, bool playSound);
|
||||
static bool command_host(UNUSED const char* message) {
|
||||
djui_panel_do_host(false, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_rehost(UNUSED const char* message) {
|
||||
network_rehost_begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_stop_hosting(UNUSED const char* message) {
|
||||
network_reset_reconnect_and_rehost();
|
||||
network_shutdown(true, false, false, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_disconnect(UNUSED const char* message) {
|
||||
network_reset_reconnect_and_rehost();
|
||||
network_shutdown(true, false, false, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_command_active(const char* name, bool active) {
|
||||
struct Command* command = get_command(name);
|
||||
if (command) command->active = active;
|
||||
}
|
||||
|
||||
struct Command* get_command(const char* name) {
|
||||
for (unsigned int i = 0; i < sCommandCount; i++) {
|
||||
if (strcmp(sCommands[i].command, name) == 0) {
|
||||
return &sCommands[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void command_message_create(const char* message, OPTIONAL enum ConsoleMessageLevel level) {
|
||||
if (gDjuiChatBoxFocus) {
|
||||
size_t newMsgLength = strlen(message) + 12;
|
||||
char newMsg[newMsgLength];
|
||||
switch (level) {
|
||||
case CONSOLE_MESSAGE_INFO:
|
||||
snprintf(newMsg, newMsgLength, "\\#dcdcdc\\%s", message);
|
||||
break;
|
||||
case CONSOLE_MESSAGE_WARNING:
|
||||
snprintf(newMsg, newMsgLength, "\\#ffffa0\\%s", message);
|
||||
break;
|
||||
case CONSOLE_MESSAGE_ERROR:
|
||||
snprintf(newMsg, newMsgLength, "\\#ffa0a0\\%s", message);
|
||||
break;
|
||||
default:
|
||||
snprintf(newMsg, newMsgLength, "\\#dcdcdc\\%s", message);
|
||||
break;
|
||||
}
|
||||
djui_chat_message_create(newMsg);
|
||||
} else {
|
||||
djui_console_message_create(message, level);
|
||||
char* colorCode;
|
||||
switch (level) {
|
||||
case CONSOLE_MESSAGE_WARNING: colorCode = "\x1b[33m"; break;
|
||||
case CONSOLE_MESSAGE_ERROR: colorCode = "\x1b[31m"; break;
|
||||
default: colorCode = "\x1b[0m"; break;
|
||||
}
|
||||
log_to_terminal("%s%s\x1b[0m\n", colorCode, message);
|
||||
}
|
||||
}
|
||||
|
||||
void run_command(char* command) {
|
||||
// directly set active state of certain commands
|
||||
set_command_active("nametags", gServerSettings.nametags);
|
||||
set_command_active("host", gDjuiInMainMenu);
|
||||
set_command_active("rehost", gNetworkType == NT_SERVER && !gDjuiInMainMenu);
|
||||
set_command_active("stop-hosting", gNetworkType == NT_SERVER && !gDjuiInMainMenu);
|
||||
set_command_active("disconnect", gNetworkType == NT_CLIENT && !gDjuiInMainMenu);
|
||||
|
||||
// directly check help command
|
||||
if (strcmp(command, "help") == 0 || strcmp(command, "?") == 0 || strcmp(command, "") == 0) {
|
||||
command_help(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// loop through builtin commands first
|
||||
for (unsigned int i = 0; i < sCommandCount; i++) {
|
||||
// sanity checks
|
||||
if (sCommands[i].command[0] == '\0') continue;
|
||||
if (!sCommands[i].action) continue;
|
||||
if (!sCommands[i].active) continue;
|
||||
if (!sCommands[i].isChatCommand && gDjuiChatBoxFocus) continue;
|
||||
|
||||
// compare strings
|
||||
size_t commandLength = strlen(sCommands[i].command);
|
||||
if (!str_starts_with(command, sCommands[i].command)) continue;
|
||||
if (command[commandLength] != '\0' && command[commandLength] != ' ') continue;
|
||||
|
||||
// get args
|
||||
char* arguments = command + commandLength;
|
||||
if (*arguments != '\0') arguments++;
|
||||
|
||||
// run action
|
||||
if (sCommands[i].action(arguments)) return;
|
||||
}
|
||||
|
||||
#ifdef DEVELOPMENT
|
||||
// check development commands
|
||||
if (exec_dev_chat_command(command)) return;
|
||||
#endif
|
||||
|
||||
// check lua commands
|
||||
if (smlua_call_chat_command_hook(command)) return;
|
||||
|
||||
// no command exists, alert the user
|
||||
char extendedUnknownCommandMessage[MAX_CONSOLE_INPUT_LENGTH];
|
||||
snprintf(extendedUnknownCommandMessage, sizeof(extendedUnknownCommandMessage), "%s (/help)", DLANG(CHAT, UNRECOGNIZED));
|
||||
command_message_create(extendedUnknownCommandMessage, CONSOLE_MESSAGE_INFO);
|
||||
}
|
||||
17
src/pc/commands.h
Normal file
17
src/pc/commands.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#define MAX_COMMAND_LEN 128
|
||||
// only applies to builtin commands
|
||||
#define MAX_COMMAND_DESC_LEN 512
|
||||
|
||||
struct Command {
|
||||
char command[MAX_COMMAND_LEN];
|
||||
char description[MAX_COMMAND_DESC_LEN];
|
||||
bool (*action)(const char*);
|
||||
bool active;
|
||||
bool isChatCommand;
|
||||
};
|
||||
|
||||
struct Command* get_command(const char* name);
|
||||
void run_command(char* command);
|
||||
void command_message_create(const char* message, OPTIONAL enum ConsoleMessageLevel level);
|
||||
|
|
@ -879,7 +879,7 @@ void configfile_save(const char *filename) {
|
|||
return;
|
||||
}
|
||||
|
||||
printf("Saving configuration to '%s'\n", filename);
|
||||
LOG_INFO("Saving configuration to '%s'\n", filename);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
|
||||
const struct ConfigOption *option = &options[i];
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@
|
|||
#include <time.h>
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/djui/djui_console.h"
|
||||
#include "pc/terminal.h"
|
||||
|
||||
static void _debuglog_print_timestamp(void) {
|
||||
#define MAX_LOG_SIZE 8192
|
||||
|
||||
static int _debuglog_print_timestamp(char* buffer, size_t bufferSize) {
|
||||
time_t ltime = time(NULL);
|
||||
#if defined(_WIN32)
|
||||
char* str = asctime(localtime(<ime));
|
||||
|
|
@ -15,32 +18,64 @@ static void _debuglog_print_timestamp(void) {
|
|||
localtime_r(<ime, <ime2);
|
||||
char* str = asctime(<ime2);
|
||||
#endif
|
||||
printf("%.*s", (int)strlen(str) - 1, str);
|
||||
return snprintf(buffer, bufferSize, "%.*s", (int)strlen(str) - 1, str);
|
||||
}
|
||||
|
||||
static void _debuglog_print_network_type(void) {
|
||||
printf(" [%02d] ", (gNetworkPlayerLocal != NULL) ? gNetworkPlayerLocal->globalIndex : -1);
|
||||
static int _debuglog_print_network_type(char* buffer, size_t bufferSize) {
|
||||
return snprintf(buffer, bufferSize, " [%02d] ", (gNetworkPlayerLocal != NULL) ? gNetworkPlayerLocal->globalIndex : -1);
|
||||
}
|
||||
|
||||
static void _debuglog_print_log_type(const char* logType) {
|
||||
printf("[%s] ", logType);
|
||||
static int _debuglog_print_log_type(const char* logType, char* buffer, size_t bufferSize) {
|
||||
return snprintf(buffer, bufferSize, "[%s] ", logType);
|
||||
}
|
||||
|
||||
static void _debuglog_print_short_filename(const char* filename) {
|
||||
static int _debuglog_print_short_filename(const char* filename, char* buffer, size_t bufferSize) {
|
||||
const char* last = strrchr(filename, '/');
|
||||
if (last != NULL) {
|
||||
printf("%s: ", last + 1);
|
||||
return snprintf(buffer, bufferSize, "%s: ", last + 1);
|
||||
}
|
||||
else {
|
||||
printf("???: ");
|
||||
return snprintf(buffer, bufferSize, "???: ");
|
||||
}
|
||||
}
|
||||
|
||||
static void _debuglog_print_log(const char* logType, char* filename) {
|
||||
_debuglog_print_timestamp();
|
||||
_debuglog_print_network_type();
|
||||
_debuglog_print_log_type(logType);
|
||||
_debuglog_print_short_filename(filename);
|
||||
static inline void _debuglog_print_log(const char* color, const char* logType, const char* filename, const char* fmt, ...) {
|
||||
char log[MAX_LOG_SIZE];
|
||||
size_t capacity = MAX_LOG_SIZE;
|
||||
char* buffer = log;
|
||||
|
||||
int len = 0;
|
||||
|
||||
len = snprintf(buffer, capacity, "%s", color);
|
||||
if (len < 0 || (size_t)len >= capacity) return;
|
||||
buffer += len; capacity -= len;
|
||||
|
||||
len = _debuglog_print_timestamp(buffer, capacity);
|
||||
if (len < 0 || (size_t)len >= capacity) return;
|
||||
buffer += len; capacity -= len;
|
||||
|
||||
len = _debuglog_print_network_type(buffer, capacity);
|
||||
if (len < 0 || (size_t)len >= capacity) return;
|
||||
buffer += len; capacity -= len;
|
||||
|
||||
len = _debuglog_print_log_type(logType, buffer, capacity);
|
||||
if (len < 0 || (size_t)len >= capacity) return;
|
||||
buffer += len; capacity -= len;
|
||||
|
||||
len = _debuglog_print_short_filename(filename, buffer, capacity);
|
||||
if (len < 0 || (size_t)len >= capacity) return;
|
||||
buffer += len; capacity -= len;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
len = vsnprintf(buffer, capacity, fmt, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
if (len < 0) return;
|
||||
|
||||
log_to_terminal("%s\x1b[0m\n", log);
|
||||
}
|
||||
|
||||
#if defined(DISABLE_MODULE_LOG)
|
||||
|
|
@ -48,9 +83,9 @@ static void _debuglog_print_log(const char* logType, char* filename) {
|
|||
#define LOG_INFO(...)
|
||||
#define LOG_ERROR(...)
|
||||
#else
|
||||
#define LOG_DEBUG(...) (configDebugPrint ? ( _debuglog_print_log("DEBUG", __FILE__), printf(__VA_ARGS__), printf("\n") ) : 0)
|
||||
#define LOG_INFO(...) ((configDebugInfo || gCLIOpts.headless) ? ( _debuglog_print_log("INFO", __FILE__), printf(__VA_ARGS__), printf("\n") ) : 0)
|
||||
#define LOG_ERROR(...) (configDebugError ? ( _debuglog_print_log("ERROR", __FILE__), printf(__VA_ARGS__), printf("\n") ) : 0)
|
||||
#define LOG_DEBUG(...) (configDebugPrint ? ( _debuglog_print_log("", "DEBUG", __FILE__, __VA_ARGS__) ) : 0)
|
||||
#define LOG_INFO(...) ((configDebugInfo || gCLIOpts.headless) ? ( _debuglog_print_log("", "INFO", __FILE__, __VA_ARGS__) ) : 0)
|
||||
#define LOG_ERROR(...) (configDebugError ? ( _debuglog_print_log("\x1b[31m", "ERROR", __FILE__, __VA_ARGS__) ) : 0)
|
||||
#endif
|
||||
#define LOG_CONSOLE(...) { snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_INFO); }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "pc/lua/smlua_hooks.h"
|
||||
#include "pc/djui/djui_language.h"
|
||||
#include "pc/djui/djui_chat_message.h"
|
||||
#include "pc/chat_commands.h"
|
||||
#include "pc/commands.h"
|
||||
#include "pc/network/ban_list.h"
|
||||
#include "pc/network/moderator_list.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
|
@ -66,12 +66,12 @@ static s32 get_level_abbreviation_alt(const char *str) {
|
|||
}
|
||||
|
||||
bool exec_dev_chat_command(char* command) {
|
||||
if (strcmp("/warp", command) == 0) {
|
||||
if (strcmp("warp", command) == 0) {
|
||||
djui_chat_message_create("Missing parameters: [LEVEL] [AREA] [ACT]");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/warp ")) {
|
||||
if (str_starts_with(command, "warp ")) {
|
||||
static const struct { const char *name; s32 num; } sLevelNumByName[] = {
|
||||
#undef STUB_LEVEL
|
||||
#undef DEFINE_LEVEL
|
||||
|
|
@ -85,7 +85,7 @@ bool exec_dev_chat_command(char* command) {
|
|||
s32 act = 0;
|
||||
|
||||
// Params
|
||||
char *paramLevel = command + 6;
|
||||
char *paramLevel = command + 5;
|
||||
if (*paramLevel == 0 || *paramLevel == ' ') {
|
||||
djui_chat_message_create("Missing parameters: [LEVEL]");
|
||||
return true;
|
||||
|
|
@ -161,23 +161,23 @@ bool exec_dev_chat_command(char* command) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (strcmp("/lua", command) == 0) {
|
||||
if (strcmp("lua", command) == 0) {
|
||||
djui_chat_message_create("Missing parameter: [LUA]");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/lua ")) {
|
||||
smlua_exec_str(&command[5]);
|
||||
if (str_starts_with(command, "lua ")) {
|
||||
smlua_exec_str(&command[4]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp("/luaf", command) == 0) {
|
||||
if (strcmp("luaf", command) == 0) {
|
||||
djui_chat_message_create("Missing parameter: [FILENAME]");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with(command, "/luaf ")) {
|
||||
smlua_exec_file(&command[6]);
|
||||
if (str_starts_with(command, "luaf ")) {
|
||||
smlua_exec_file(&command[5]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -185,8 +185,8 @@ bool exec_dev_chat_command(char* command) {
|
|||
}
|
||||
|
||||
void dev_display_chat_commands(void) {
|
||||
djui_chat_message_create("/warp [LEVEL] [AREA] [ACT] - Level can be either a numeric value or a shorthand name");
|
||||
djui_chat_message_create("/lua [LUA] - Execute Lua code from a string");
|
||||
djui_chat_message_create("/luaf [FILENAME] - Execute Lua code from a file");
|
||||
command_message_create("/warp [LEVEL] [AREA] [ACT] - Level can be either a numeric value or a shorthand name");
|
||||
command_message_create("/lua [LUA] - Execute Lua code from a string");
|
||||
command_message_create("/luaf [FILENAME] - Execute Lua code from a file");
|
||||
}
|
||||
#endif
|
||||
|
|
@ -46,7 +46,7 @@ void discord_fatal(int rc) {
|
|||
}
|
||||
|
||||
static void get_oauth2_token_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordOAuth2Token* token) {
|
||||
LOG_INFO("> get_oauth2_token_callback returned %d", result);
|
||||
LOG_INFO("get_oauth2_token_callback returned %d", result);
|
||||
if (result != DiscordResult_Ok) { return; }
|
||||
LOG_INFO("OAuth2 token: %s", token->access_token);
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ static void register_launch_command(void) {
|
|||
}
|
||||
|
||||
static void on_current_user_update(UNUSED void* data) {
|
||||
LOG_INFO("> on_current_user_update");
|
||||
LOG_INFO("on_current_user_update");
|
||||
struct DiscordUser user = { 0 };
|
||||
app.users->get_current_user(app.users, &user);
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ static void on_current_user_update(UNUSED void* data) {
|
|||
}
|
||||
|
||||
struct IDiscordUserEvents* discord_user_initialize(void) {
|
||||
LOG_INFO("> discord_user_intitialize");
|
||||
LOG_INFO("discord_user_intitialize");
|
||||
static struct IDiscordUserEvents events = { 0 };
|
||||
events.on_current_user_update = on_current_user_update;
|
||||
return &events;
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ static uint64_t sQueuedLobbyId = 0;
|
|||
static char sQueuedLobbyPassword[64] = "";
|
||||
|
||||
static void on_activity_update_callback(UNUSED void* data, enum EDiscordResult result) {
|
||||
LOG_INFO("> on_activity_update_callback returned %d", result);
|
||||
LOG_INFO("on_activity_update_callback returned %d", result);
|
||||
DISCORD_REQUIRE(result);
|
||||
}
|
||||
|
||||
static void on_activity_join(UNUSED void* data, const char* secret) {
|
||||
LOG_INFO("> on_activity_join, secret: %s", secret);
|
||||
LOG_INFO("on_activity_join, secret: %s", secret);
|
||||
char *token;
|
||||
|
||||
// extract lobby type
|
||||
|
|
@ -52,12 +52,12 @@ static void on_activity_join(UNUSED void* data, const char* secret) {
|
|||
}
|
||||
|
||||
static void on_activity_join_request_callback(UNUSED void* data, enum EDiscordResult result) {
|
||||
LOG_INFO("> on_activity_join_request_callback returned %d", (int)result);
|
||||
LOG_INFO("on_activity_join_request_callback returned %d", (int)result);
|
||||
DISCORD_REQUIRE(result);
|
||||
}
|
||||
|
||||
static void on_activity_join_request(UNUSED void* data, struct DiscordUser* user) {
|
||||
LOG_INFO("> on_activity_join_request from " DISCORD_ID_FORMAT, user->id);
|
||||
LOG_INFO("on_activity_join_request from " DISCORD_ID_FORMAT, user->id);
|
||||
}
|
||||
|
||||
static void strncat_len(char* destination, char* source, size_t destinationLength, size_t sourceLength) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <string.h>
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
#include "pc/chat_commands.h"
|
||||
#include "pc/commands.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "djui.h"
|
||||
#include "engine/math_util.h"
|
||||
|
|
@ -139,13 +139,7 @@ static void djui_chat_box_input_enter(struct DjuiInputbox* chatInput) {
|
|||
if (strlen(chatInput->buffer) != 0) {
|
||||
sent_history_add_message(&sentHistory, chatInput->buffer);
|
||||
if (chatInput->buffer[0] == '/') {
|
||||
if (strcmp(chatInput->buffer, "/help") == 0 || strcmp(chatInput->buffer, "/?") == 0 || strcmp(chatInput->buffer, "/") == 0) {
|
||||
display_chat_commands();
|
||||
} else if (!exec_chat_command(chatInput->buffer)) {
|
||||
char extendedUnknownCommandMessage[MAX_CHAT_MSG_LENGTH];
|
||||
snprintf(extendedUnknownCommandMessage, sizeof(extendedUnknownCommandMessage), "%s (/help)", DLANG(CHAT, UNRECOGNIZED));
|
||||
djui_chat_message_create(extendedUnknownCommandMessage);
|
||||
}
|
||||
run_command(chatInput->buffer + 1);
|
||||
} else {
|
||||
djui_chat_message_create_from(gNetworkPlayerLocal->globalIndex, chatInput->buffer);
|
||||
network_send_chat(chatInput->buffer, gNetworkPlayerLocal->globalIndex);
|
||||
|
|
@ -417,7 +411,7 @@ static bool djui_chat_box_input_on_key_down(UNUSED struct DjuiBase* base, int sc
|
|||
sent_history_init(&sentHistory);
|
||||
|
||||
if (gDjuiChatBox == NULL) { return false; }
|
||||
|
||||
|
||||
f32 pageAmount = gDjuiChatBox->chatContainer->base.elem.height * 3.0f / 4.0f;
|
||||
|
||||
char previousText[MAX_CHAT_MSG_LENGTH];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "djui.h"
|
||||
#include "djui_console.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "pc/commands.h"
|
||||
#include "engine/math_util.h"
|
||||
|
||||
#define MAX_CONSOLE_MESSAGES 500
|
||||
|
|
@ -12,6 +13,7 @@ bool gDjuiConsoleFocus = false;
|
|||
char gDjuiConsoleTmpBuffer[CONSOLE_MAX_TMP_BUFFER] = "";
|
||||
u32 sDjuiConsoleMessages = 0;
|
||||
bool sDjuiConsoleQueueMessages = true;
|
||||
bool sClearConsoleInput = false;
|
||||
|
||||
struct ConsoleQueuedMessage {
|
||||
char* message;
|
||||
|
|
@ -52,18 +54,25 @@ void djui_console_message_dequeue(void) {
|
|||
|
||||
bool djui_console_render(struct DjuiBase* base) {
|
||||
struct DjuiConsole* console = (struct DjuiConsole*)base;
|
||||
djui_base_set_size(base, gDjuiRoot->base.width.value, gDjuiRoot->base.height.value * 0.5f);
|
||||
djui_base_set_size(&console->base, gDjuiRoot->base.width.value, gDjuiRoot->base.height.value * 0.5f);
|
||||
djui_base_set_size(&console->rectContainer->base, gDjuiRoot->base.width.value, gDjuiRoot->base.height.value * 0.5f - 32);
|
||||
if (console->scrolling) {
|
||||
f32 yMax = console->base.comp.height - console->flow->base.height.value;
|
||||
f32 yMax = console->base.comp.height - console->flow->base.height.value - 32;
|
||||
f32 target = console->flow->base.y.value + (console->scrollY - console->flow->base.y.value) * (configSmoothScrolling ? 0.5f : 1.f);
|
||||
|
||||
console->flow->base.y.value = clamp(target, yMax, 0.f);
|
||||
console->flow->base.y.value = clamp(target, yMax, 0.0f);
|
||||
if (target < yMax || 0.f < target) {
|
||||
console->scrollY = clamp(target, yMax, 0.f);
|
||||
if (target > 0.f) { gDjuiConsole->scrolling = false; }
|
||||
}
|
||||
} else { console->scrollY = console->flow->base.y.value; }
|
||||
|
||||
if (sClearConsoleInput) {
|
||||
djui_inputbox_set_text(gDjuiConsole->inputbox, "");
|
||||
djui_inputbox_select_all(gDjuiConsole->inputbox);
|
||||
sClearConsoleInput = false;
|
||||
}
|
||||
|
||||
djui_rect_render(base);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -75,12 +84,13 @@ static void djui_console_destroy(struct DjuiBase* base) {
|
|||
|
||||
void djui_console_toggle(void) {
|
||||
if (gDjuiConsole == NULL) { return; }
|
||||
sClearConsoleInput = true;
|
||||
gDjuiConsoleFocus = !gDjuiConsoleFocus;
|
||||
djui_base_set_visible(&gDjuiConsole->base, gDjuiConsoleFocus);
|
||||
|
||||
if (gDjuiConsoleFocus) {
|
||||
if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); }
|
||||
djui_interactable_set_input_focus(&gDjuiConsole->base);
|
||||
djui_interactable_set_input_focus(&gDjuiConsole->inputbox->base);
|
||||
} else {
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
}
|
||||
|
|
@ -96,18 +106,33 @@ static void djui_console_on_scroll(UNUSED struct DjuiBase *base, UNUSED float x,
|
|||
if (gDjuiInputHeldShift) { y *= 3; }
|
||||
|
||||
gDjuiConsole->scrollY -= y;
|
||||
|
||||
|
||||
if (!gDjuiConsole->scrolling) {
|
||||
gDjuiConsole->scrolling = y > 0 && gDjuiConsole->scrollY > yMax;
|
||||
}
|
||||
}
|
||||
|
||||
static bool djui_console_on_key_down(UNUSED struct DjuiBase* base, int scancode) {
|
||||
static void djui_console_enter() {
|
||||
char* buffer = gDjuiConsole->inputbox->buffer;
|
||||
if (strcmp(buffer, "") == 0) return;
|
||||
if (buffer[0] == '/') buffer++;
|
||||
run_command(buffer);
|
||||
sClearConsoleInput = true;
|
||||
}
|
||||
|
||||
static bool djui_console_on_key_down(struct DjuiBase* base, int scancode) {
|
||||
if (gDjuiConsole == NULL) { return false; }
|
||||
f32 yMax = gDjuiConsole->base.comp.height - gDjuiConsole->flow->base.height.value;
|
||||
|
||||
f32 pageAmount = gDjuiConsole->base.comp.height * 3.0f / 4.0f;
|
||||
|
||||
for (int i = 0; i < MAX_BINDS; i++) {
|
||||
if (scancode == (int)configKeyConsole[i]) {
|
||||
djui_console_toggle();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (scancode) {
|
||||
case SCANCODE_UP:
|
||||
gDjuiConsole->scrollY -= 15;
|
||||
|
|
@ -121,8 +146,14 @@ static bool djui_console_on_key_down(UNUSED struct DjuiBase* base, int scancode)
|
|||
case SCANCODE_PAGE_DOWN:
|
||||
gDjuiConsole->scrollY += pageAmount;
|
||||
break;
|
||||
case SCANCODE_ESCAPE: djui_console_toggle(); break;
|
||||
default: break;
|
||||
case SCANCODE_ENTER:
|
||||
djui_console_enter();
|
||||
break;
|
||||
case SCANCODE_ESCAPE:
|
||||
djui_console_toggle();
|
||||
break;
|
||||
default:
|
||||
return djui_inputbox_on_key_down(base, scancode);
|
||||
}
|
||||
|
||||
if (!gDjuiConsole->scrolling) {
|
||||
|
|
@ -131,6 +162,23 @@ static bool djui_console_on_key_down(UNUSED struct DjuiBase* base, int scancode)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void djui_console_on_text_input(struct DjuiBase* base, char* text) {
|
||||
djui_inputbox_on_text_input(base, text);
|
||||
}
|
||||
|
||||
void djui_console_clear() {
|
||||
if (gDjuiConsole == NULL) { return; }
|
||||
|
||||
struct DjuiBase* cfBase = &gDjuiConsole->flow->base;
|
||||
djui_base_destroy_children(cfBase);
|
||||
|
||||
cfBase->height.value = 0;
|
||||
cfBase->y.value = 0;
|
||||
gDjuiConsole->scrollY = 0;
|
||||
gDjuiConsole->scrolling = false;
|
||||
sDjuiConsoleMessages = 0;
|
||||
}
|
||||
|
||||
void djui_console_message_create(const char* message, enum ConsoleMessageLevel level) {
|
||||
if (sDjuiConsoleQueueMessages || !gDjuiConsole) {
|
||||
djui_console_message_queue(message, level);
|
||||
|
|
@ -205,11 +253,13 @@ struct DjuiConsole* djui_console_create(void) {
|
|||
djui_base_set_padding(base, 0, 8, 8, 8);
|
||||
djui_base_set_visible(base, false);
|
||||
|
||||
djui_interactable_create(base, NULL);
|
||||
djui_interactable_hook_key(base, djui_console_on_key_down, NULL);
|
||||
djui_interactable_hook_scroll(base, djui_console_on_scroll);
|
||||
struct DjuiRect* rectContainer = djui_rect_container_create(base, 0);
|
||||
djui_base_set_alignment(&rectContainer->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
djui_base_set_size_type(&rectContainer->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&rectContainer->base, 1.0f, gDjuiRoot->base.height.value * 0.5f);
|
||||
console->rectContainer = rectContainer;
|
||||
|
||||
struct DjuiFlowLayout* flow = djui_flow_layout_create(base);
|
||||
struct DjuiFlowLayout* flow = djui_flow_layout_create(&rectContainer->base);
|
||||
struct DjuiBase* cfBase = &flow->base;
|
||||
djui_base_set_alignment(cfBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
|
||||
djui_base_set_location(cfBase, 0, 0);
|
||||
|
|
@ -223,6 +273,21 @@ struct DjuiConsole* djui_console_create(void) {
|
|||
cfBase->abandonAfterChildRenderFail = true;
|
||||
console->flow = flow;
|
||||
|
||||
struct DjuiInputbox* inputbox = djui_inputbox_create(base, MAX_CONSOLE_INPUT_LENGTH);
|
||||
inputbox->base.interactable->update_style = NULL;
|
||||
djui_base_set_border_color(&inputbox->base, 0, 0, 0, 0);
|
||||
djui_base_set_color(&inputbox->base, 0, 0, 0, 0);
|
||||
djui_base_set_size_type(&inputbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&inputbox->base, 1.0f, 32);
|
||||
djui_base_set_alignment(&inputbox->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
|
||||
djui_interactable_hook_key(&inputbox->base, djui_console_on_key_down, djui_inputbox_on_key_up);
|
||||
djui_interactable_hook_text_input(&inputbox->base, djui_console_on_text_input);
|
||||
djui_interactable_hook_text_editing(&inputbox->base, djui_inputbox_on_text_editing);
|
||||
djui_interactable_hook_scroll(&inputbox->base, djui_console_on_scroll);
|
||||
djui_inputbox_set_text_color(inputbox, 255, 255, 255, 255);
|
||||
inputbox->yOffset = 6;
|
||||
console->inputbox = inputbox;
|
||||
|
||||
gDjuiConsole = console;
|
||||
|
||||
return console;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include "djui.h"
|
||||
|
||||
#define MAX_CONSOLE_INPUT_LENGTH 500
|
||||
|
||||
enum ConsoleMessageLevel {
|
||||
CONSOLE_MESSAGE_INFO,
|
||||
CONSOLE_MESSAGE_WARNING,
|
||||
|
|
@ -9,7 +11,9 @@ enum ConsoleMessageLevel {
|
|||
|
||||
struct DjuiConsole {
|
||||
struct DjuiBase base;
|
||||
struct DjuiRect* rectContainer;
|
||||
struct DjuiFlowLayout* flow;
|
||||
struct DjuiInputbox* inputbox;
|
||||
bool scrolling;
|
||||
f32 scrollY;
|
||||
};
|
||||
|
|
@ -20,6 +24,7 @@ extern bool gDjuiConsoleFocus;
|
|||
extern char gDjuiConsoleTmpBuffer[];
|
||||
|
||||
void djui_console_message_dequeue(void);
|
||||
void djui_console_clear();
|
||||
void djui_console_message_create(const char* message, enum ConsoleMessageLevel level);
|
||||
/* |description|Toggles the visibility of the DJUI console|descriptionEnd| */
|
||||
void djui_console_toggle(void);
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
|
|||
inputbox->selection[1] = inputbox->selection[0];
|
||||
sCursorBlink = 0;
|
||||
djui_inputbox_on_change(inputbox);
|
||||
|
||||
|
||||
inputbox->imePos = 0;
|
||||
if (inputbox->imeBuffer != NULL) {
|
||||
free(inputbox->imeBuffer);
|
||||
|
|
@ -408,9 +408,9 @@ void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
|
|||
void djui_inputbox_on_text_editing(struct DjuiBase *base, char* text, int cursorPos) {
|
||||
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
|
||||
inputbox->imePos = (u16)cursorPos;
|
||||
|
||||
|
||||
if (inputbox->imeBuffer != NULL) free(inputbox->imeBuffer);
|
||||
|
||||
|
||||
if (*text == '\0') {
|
||||
inputbox->imeBuffer = NULL;
|
||||
}
|
||||
|
|
@ -420,7 +420,7 @@ void djui_inputbox_on_text_editing(struct DjuiBase *base, char* text, int cursor
|
|||
strcpy(copy,text);
|
||||
inputbox->imeBuffer = copy;
|
||||
}
|
||||
|
||||
|
||||
djui_inputbox_on_change(inputbox);
|
||||
}
|
||||
|
||||
|
|
@ -469,9 +469,9 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
|
|||
}
|
||||
|
||||
sCursorBlink = (sCursorBlink + 1) % DJUI_INPUTBOX_MAX_BLINK;
|
||||
|
||||
|
||||
f32 renderX = x;
|
||||
|
||||
|
||||
u16 imePos = inputbox->imePos;
|
||||
if (imePos != 0) {
|
||||
char* ime = inputbox->imeBuffer;
|
||||
|
|
@ -480,13 +480,13 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
|
|||
ime = djui_unicode_next_char(ime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// render only cursor when there is no selection width
|
||||
if (selection[0] == selection[1]) {
|
||||
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK && djui_interactable_is_input_focus(&inputbox->base)) {
|
||||
create_dl_translation_matrix(DJUI_MTX_PUSH, renderX - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0);
|
||||
create_dl_scale_matrix(DJUI_MTX_NOPUSH, DJUI_INPUTBOX_CURSOR_WIDTH, 0.8f, 1.0f);
|
||||
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
|
||||
gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a);
|
||||
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
|
||||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
}
|
||||
|
|
@ -559,7 +559,7 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
|
|||
|
||||
// translate position
|
||||
f32 translatedX = comp->x + inputbox->viewX;
|
||||
f32 translatedY = comp->y + DJUI_INPUTBOX_YOFF;
|
||||
f32 translatedY = comp->y + inputbox->yOffset;
|
||||
djui_gfx_position_translate(&translatedX, &translatedY);
|
||||
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0);
|
||||
|
||||
|
|
@ -584,7 +584,7 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
|
|||
u16 selection[2] = { 0 };
|
||||
selection[0] = fmin(inputbox->selection[0], inputbox->selection[1]);
|
||||
selection[1] = fmax(inputbox->selection[0], inputbox->selection[1]);
|
||||
|
||||
|
||||
// render text
|
||||
char* c = inputbox->buffer;
|
||||
f32 drawX = inputbox->viewX;
|
||||
|
|
@ -593,7 +593,7 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
|
|||
|
||||
font->render_begin();
|
||||
for (u16 i = 0; i < inputbox->bufferSize; i++) {
|
||||
|
||||
|
||||
//render composition text
|
||||
if (selection[0] == i && inputbox->imeBuffer != NULL) {
|
||||
char *ime = inputbox->imeBuffer;
|
||||
|
|
@ -602,7 +602,7 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
|
|||
ime = djui_unicode_next_char(ime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (*c == '\0') { break; }
|
||||
|
||||
// deal with seleciton color
|
||||
|
|
@ -638,6 +638,7 @@ struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSiz
|
|||
struct DjuiBase* base = &inputbox->base;
|
||||
inputbox->bufferSize = bufferSize;
|
||||
inputbox->buffer = calloc(bufferSize, sizeof(char));
|
||||
inputbox->yOffset = DJUI_INPUTBOX_YOFF;
|
||||
|
||||
djui_base_init(parent, base, djui_inputbox_render, djui_inputbox_destroy);
|
||||
djui_base_set_size(base, 200, 32);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ struct DjuiInputbox {
|
|||
u16 bufferSize;
|
||||
u16 selection[2];
|
||||
f32 viewX;
|
||||
f32 yOffset;
|
||||
struct DjuiColor textColor;
|
||||
void (*on_enter_press)(struct DjuiInputbox*);
|
||||
void (*on_escape_press)(struct DjuiInputbox*);
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ void djui_interactable_set_binding(struct DjuiBase* base) {
|
|||
}
|
||||
|
||||
void djui_interactable_set_input_focus(struct DjuiBase* base) {
|
||||
if (gDjuiConsoleFocus && base != &gDjuiConsole->base) {
|
||||
if (gDjuiConsoleFocus && base != &gDjuiConsole->inputbox->base) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -199,8 +199,8 @@ bool djui_interactable_on_key_down(int scancode) {
|
|||
}
|
||||
|
||||
bool keyFocused = (gInteractableFocus != NULL)
|
||||
&& (gInteractableFocus->interactable != NULL)
|
||||
&& (gInteractableFocus->interactable->on_key_down != NULL);
|
||||
&& (gInteractableFocus->interactable != NULL)
|
||||
&& (gInteractableFocus->interactable->on_key_down != NULL);
|
||||
|
||||
if (keyFocused) {
|
||||
bool consume = gInteractableFocus->interactable->on_key_down(gInteractableFocus, scancode);
|
||||
|
|
@ -217,10 +217,22 @@ bool djui_interactable_on_key_down(int scancode) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!gDjuiChatBoxFocus) {
|
||||
for (int i = 0; i < MAX_BINDS; i++) {
|
||||
if (scancode == (int)configKeyConsole[i]) {
|
||||
djui_console_toggle();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gDjuiChatBox != NULL && !gDjuiChatBoxFocus) {
|
||||
bool pressChat = false;
|
||||
for (int i = 0; i < MAX_BINDS; i++) {
|
||||
if (scancode == (int)configKeyChat[i]) { pressChat = true; }
|
||||
if (scancode == (int)configKeyChat[i]) {
|
||||
pressChat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pressChat && !gDjuiConsoleFocus) {
|
||||
|
|
@ -264,7 +276,7 @@ bool djui_interactable_on_key_down(int scancode) {
|
|||
}
|
||||
}
|
||||
|
||||
if (gDjuiChatBoxFocus || djui_panel_is_active()) {
|
||||
if (gDjuiConsoleFocus || gDjuiChatBoxFocus || djui_panel_is_active()) {
|
||||
switch (scancode) {
|
||||
case SCANCODE_UP: sKeyboardHoldDirection = PAD_HOLD_DIR_UP; return true;
|
||||
case SCANCODE_DOWN: sKeyboardHoldDirection = PAD_HOLD_DIR_DOWN; return true;
|
||||
|
|
@ -278,13 +290,6 @@ bool djui_interactable_on_key_down(int scancode) {
|
|||
}
|
||||
|
||||
void djui_interactable_on_key_up(int scancode) {
|
||||
|
||||
if (!gDjuiChatBoxFocus) {
|
||||
for (int i = 0; i < MAX_BINDS; i++) {
|
||||
if (scancode == (int)configKeyConsole[i]) { djui_console_toggle(); break; }
|
||||
}
|
||||
}
|
||||
|
||||
if (gDjuiPlayerList != NULL || gDjuiModList != NULL) {
|
||||
for (int i = 0; i < MAX_BINDS; i++) {
|
||||
if (scancode == (int)configKeyPlayerList[i]) {
|
||||
|
|
@ -424,12 +429,12 @@ void djui_interactable_update(void) {
|
|||
u16 mainButtons = PAD_BUTTON_A | PAD_BUTTON_B;
|
||||
if ((mouseButtons & MOUSE_BUTTON_1) && !(sLastMouseButtons & MOUSE_BUTTON_1) && !djui_cursor_inside_base(gInteractableFocus)) {
|
||||
// clicked outside of focus
|
||||
if (!gDjuiChatBoxFocus) {
|
||||
if (!gDjuiChatBoxFocus && !gDjuiConsoleFocus) {
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
}
|
||||
} else if ((padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) {
|
||||
// pressed main face button
|
||||
if (!gDjuiChatBoxFocus) {
|
||||
if (!gDjuiChatBoxFocus && !gDjuiConsoleFocus) {
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -287,6 +287,11 @@ static void djui_text_read_line(struct DjuiText* text, char** message, f32* line
|
|||
break;
|
||||
}
|
||||
|
||||
// check for tab
|
||||
if (*c == '\t') {
|
||||
charWidth = 4 * text->font->char_width(" ");
|
||||
}
|
||||
|
||||
// check to see if this character would exceed size
|
||||
if (*lineWidth + charWidth >= maxLineWidth) {
|
||||
break;
|
||||
|
|
@ -390,7 +395,9 @@ static void djui_text_render_line(struct DjuiText* text, char* c1, char* c2, f32
|
|||
}
|
||||
|
||||
f32 charWidth = text->font->char_width(c);
|
||||
if (*c != '\n' && *c != ' ') {
|
||||
if (*c == '\t') {
|
||||
charWidth = 4 * text->font->char_width(" ");
|
||||
} else if (*c != '\n' && *c != ' ') {
|
||||
djui_text_render_char(text, c);
|
||||
}
|
||||
|
||||
|
|
|
|||
1762
src/pc/linenoise/linenoise.c
Normal file
1762
src/pc/linenoise/linenoise.c
Normal file
File diff suppressed because it is too large
Load diff
114
src/pc/linenoise/linenoise.h
Normal file
114
src/pc/linenoise/linenoise.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* linenoise.h -- VERSION 1.0
|
||||
*
|
||||
* Guerrilla line editing library against the idea that a line editing lib
|
||||
* needs to be 20,000 lines of C code.
|
||||
*
|
||||
* See linenoise.c for more information.
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __LINENOISE_H
|
||||
#define __LINENOISE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
||||
extern char *linenoiseEditMore;
|
||||
|
||||
/* The linenoiseState structure represents the state during line editing.
|
||||
* We pass this state to functions implementing specific editing
|
||||
* functionalities. */
|
||||
struct linenoiseState {
|
||||
int in_completion; /* The user pressed TAB and we are now in completion
|
||||
* mode, so input is handled by completeLine(). */
|
||||
size_t completion_idx; /* Index of next completion to propose. */
|
||||
int ifd; /* Terminal stdin file descriptor. */
|
||||
int ofd; /* Terminal stdout file descriptor. */
|
||||
char *buf; /* Edited line buffer. */
|
||||
size_t buflen; /* Edited line buffer size. */
|
||||
const char *prompt; /* Prompt to display. */
|
||||
size_t plen; /* Prompt length. */
|
||||
size_t pos; /* Current cursor position. */
|
||||
size_t oldpos; /* Previous refresh cursor position. */
|
||||
size_t len; /* Current edited line length. */
|
||||
size_t cols; /* Number of columns in terminal. */
|
||||
size_t oldrows; /* Rows used by last refrehsed line (multiline mode) */
|
||||
int oldrpos; /* Cursor row from last refresh (for multiline clearing). */
|
||||
int history_index; /* The history index we are currently editing. */
|
||||
};
|
||||
|
||||
typedef struct linenoiseCompletions {
|
||||
size_t len;
|
||||
char **cvec;
|
||||
} linenoiseCompletions;
|
||||
|
||||
/* Non blocking API. */
|
||||
int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt);
|
||||
char *linenoiseEditFeed(struct linenoiseState *l);
|
||||
void linenoiseEditStop(struct linenoiseState *l);
|
||||
void linenoiseHide(struct linenoiseState *l);
|
||||
void linenoiseShow(struct linenoiseState *l);
|
||||
|
||||
/* Blocking API. */
|
||||
char *linenoise(const char *prompt);
|
||||
void linenoiseFree(void *ptr);
|
||||
|
||||
/* Completion API. */
|
||||
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
|
||||
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
|
||||
typedef void(linenoiseFreeHintsCallback)(void *);
|
||||
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||
|
||||
/* History API. */
|
||||
int linenoiseHistoryAdd(const char *line);
|
||||
int linenoiseHistorySetMaxLen(int len);
|
||||
int linenoiseHistorySave(const char *filename);
|
||||
int linenoiseHistoryLoad(const char *filename);
|
||||
|
||||
/* Other utilities. */
|
||||
void linenoiseClearScreen(void);
|
||||
void linenoiseSetMultiLine(int ml);
|
||||
void linenoisePrintKeyCodes(void);
|
||||
void linenoiseMaskModeEnable(void);
|
||||
void linenoiseMaskModeDisable(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LINENOISE_H */
|
||||
|
|
@ -19,9 +19,9 @@
|
|||
#include "pc/debuglog.h"
|
||||
#include "pc/djui/djui_console.h"
|
||||
|
||||
#define LOG_LUA(...) { if (!gSmLuaSuppressErrors) { printf("[LUA] "), printf(__VA_ARGS__), printf("\n"), smlua_mod_error(), snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), sys_swap_backslashes(gDjuiConsoleTmpBuffer), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_ERROR); } }
|
||||
#define LOG_LUA_LINE(...) { if (!gSmLuaSuppressErrors) { printf("[LUA] "), printf(__VA_ARGS__), printf("\n"), smlua_mod_error(); snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), sys_swap_backslashes(gDjuiConsoleTmpBuffer), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_ERROR), smlua_logline(); } }
|
||||
#define LOG_LUA_LINE_WARNING(...) { if (!gLuaActiveMod->showedScriptWarning) { gLuaActiveMod->showedScriptWarning = true; smlua_mod_warning(); snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), sys_swap_backslashes(gDjuiConsoleTmpBuffer), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_WARNING); } }
|
||||
#define LOG_LUA(...) { if (!gSmLuaSuppressErrors) { log_to_terminal("\x1b[31m[LUA] "); log_to_terminal(__VA_ARGS__); log_to_terminal("\x1b[0m\n"); smlua_mod_error(); snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__); sys_swap_backslashes(gDjuiConsoleTmpBuffer); djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_ERROR); } }
|
||||
#define LOG_LUA_LINE(...) { if (!gSmLuaSuppressErrors) { log_to_terminal("\x1b[31m[LUA] "); log_to_terminal(__VA_ARGS__); log_to_terminal("\x1b[0m\n"); smlua_mod_error(); snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__); sys_swap_backslashes(gDjuiConsoleTmpBuffer); djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_ERROR); smlua_logline(); } }
|
||||
#define LOG_LUA_LINE_WARNING(...) { if (!gLuaActiveMod->showedScriptWarning) { gLuaActiveMod->showedScriptWarning = true; log_to_terminal("\x1b[33m[LUA] "); log_to_terminal(__VA_ARGS__); log_to_terminal("\x1b[0m\n"); smlua_mod_warning(); snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__); sys_swap_backslashes(gDjuiConsoleTmpBuffer); djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_WARNING); } }
|
||||
|
||||
#ifdef DEVELOPMENT
|
||||
#define LUA_STACK_CHECK_BEGIN_NUM(state, n) int __LUA_STACK_TOP = lua_gettop(state) + (n)
|
||||
|
|
|
|||
|
|
@ -1485,6 +1485,7 @@ char gSmluaConstants[] = ""
|
|||
"DIALOG_168=168\n"
|
||||
"DIALOG_169=169\n"
|
||||
"DIALOG_COUNT=170\n"
|
||||
"MAX_CONSOLE_INPUT_LENGTH=500\n"
|
||||
"CONSOLE_MESSAGE_INFO=0\n"
|
||||
"CONSOLE_MESSAGE_WARNING=1\n"
|
||||
"CONSOLE_MESSAGE_ERROR=2\n"
|
||||
|
|
|
|||
|
|
@ -40,6 +40,52 @@ bool smlua_functions_valid_param_range(lua_State* L, int min, int max) {
|
|||
return true;
|
||||
}
|
||||
|
||||
///////////
|
||||
// print //
|
||||
///////////
|
||||
|
||||
int smlua_func_print(lua_State *L) {
|
||||
int top = lua_gettop(L);
|
||||
|
||||
// calculate total length first
|
||||
size_t totalLen = 0;
|
||||
for (int i = 1; i <= top; i++) {
|
||||
size_t len;
|
||||
luaL_tolstring(L, i, &len);
|
||||
totalLen += len;
|
||||
if (i > 1) totalLen += 1;
|
||||
}
|
||||
|
||||
// allocate string
|
||||
char* completeString = malloc(totalLen + 1);
|
||||
if (!completeString) return 0;
|
||||
|
||||
size_t pos = 0;
|
||||
|
||||
// copy string
|
||||
for (int i = 1; i <= top; i++) {
|
||||
size_t len;
|
||||
const char* str = luaL_tolstring(L, i, &len);
|
||||
|
||||
if (i > 1) {
|
||||
completeString[pos] = '\t';
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
memcpy(completeString + pos, str, len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
completeString[pos] = '\0';
|
||||
|
||||
// print to terminal and console
|
||||
log_to_terminal("%s\n", completeString);
|
||||
djui_console_message_create(completeString, CONSOLE_MESSAGE_INFO);
|
||||
|
||||
free(completeString);
|
||||
return 1;
|
||||
}
|
||||
|
||||
///////////
|
||||
// table //
|
||||
///////////
|
||||
|
|
@ -806,6 +852,13 @@ int smlua_func_log_to_console(lua_State* L) {
|
|||
}
|
||||
|
||||
djui_console_message_create(message, level);
|
||||
char* colorCode;
|
||||
switch (level) {
|
||||
case CONSOLE_MESSAGE_WARNING: colorCode = "\x1b[33m"; break;
|
||||
case CONSOLE_MESSAGE_ERROR: colorCode = "\x1b[31m"; break;
|
||||
default: colorCode = "\x1b[0m"; break;
|
||||
}
|
||||
log_to_terminal("%s%s\x1b[0m\n", colorCode, message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1013,6 +1066,7 @@ void smlua_bind_functions(void) {
|
|||
lua_State* L = gLuaState;
|
||||
|
||||
// misc
|
||||
smlua_bind_function(L, "print", smlua_func_print);
|
||||
smlua_bind_function(L, "table_copy", smlua_func_table_copy);
|
||||
smlua_bind_function(L, "table_deepcopy", smlua_func_table_deepcopy);
|
||||
smlua_bind_function(L, "init_mario_after_warp", smlua_func_init_mario_after_warp);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "src/game/mario_step.h"
|
||||
#include "src/game/mario.h"
|
||||
#include "src/game/rumble_init.h"
|
||||
#include "src/pc/commands.h"
|
||||
#include "src/pc/djui/djui_popup.h"
|
||||
#include "src/pc/network/network_utils.h"
|
||||
#include "src/pc/djui/djui_console.h"
|
||||
|
|
@ -12125,6 +12126,32 @@ int smlua_func_update_character_anim_offset(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
////////////////
|
||||
// commands.h //
|
||||
////////////////
|
||||
|
||||
int smlua_func_command_message_create(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top < 1 || top > 2) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected between %u and %u, Received %u", "command_message_create", 1, 2, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* message = smlua_to_string(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "command_message_create"); return 0; }
|
||||
int level = (int) 0;
|
||||
if (top >= 2) {
|
||||
level = smlua_to_integer(L, 2);
|
||||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "command_message_create"); return 0; }
|
||||
}
|
||||
|
||||
command_message_create(message, level);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// djui_chat_message.h //
|
||||
/////////////////////////
|
||||
|
|
@ -37519,6 +37546,9 @@ void smlua_bind_functions_autogen(void) {
|
|||
smlua_bind_function(L, "get_character_anim", smlua_func_get_character_anim);
|
||||
smlua_bind_function(L, "update_character_anim_offset", smlua_func_update_character_anim_offset);
|
||||
|
||||
// commands.h
|
||||
smlua_bind_function(L, "command_message_create", smlua_func_command_message_create);
|
||||
|
||||
// djui_chat_message.h
|
||||
smlua_bind_function(L, "djui_chat_message_create", smlua_func_djui_chat_message_create);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include "pc/network/network.h"
|
||||
#include "pc/network/network_player.h"
|
||||
#include "pc/network/socket/socket.h"
|
||||
#include "pc/chat_commands.h"
|
||||
#include "pc/commands.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "pc/djui/djui_lua_profiler.h"
|
||||
#include "pc/djui/djui_panel.h"
|
||||
|
|
@ -1009,62 +1009,72 @@ bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* ob
|
|||
// hooked chat command //
|
||||
/////////////////////////
|
||||
|
||||
struct LuaHookedChatCommand {
|
||||
struct LuaHookedCommand {
|
||||
char* command;
|
||||
char* description;
|
||||
int reference;
|
||||
struct Mod* mod;
|
||||
struct ModFile* modFile;
|
||||
bool isConsoleCommand;
|
||||
};
|
||||
|
||||
#define MAX_HOOKED_CHAT_COMMANDS 512
|
||||
|
||||
static struct LuaHookedChatCommand sHookedChatCommands[MAX_HOOKED_CHAT_COMMANDS] = { 0 };
|
||||
static struct LuaHookedCommand sHookedChatCommands[MAX_HOOKED_CHAT_COMMANDS] = { 0 };
|
||||
static int sHookedChatCommandsCount = 0;
|
||||
|
||||
int smlua_hook_chat_command(lua_State* L) {
|
||||
int smlua_hook_command_internal(lua_State* L, bool isConsoleCommand) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 3)) { return 0; }
|
||||
|
||||
if (gLuaLoadingMod == NULL) {
|
||||
LOG_LUA_LINE("hook_chat_command() can only be called on load.");
|
||||
LOG_LUA_LINE("%s can only be called on load.", isConsoleCommand ? "hook_console_command()" : "hook_chat_command()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sHookedChatCommandsCount >= MAX_HOOKED_CHAT_COMMANDS) {
|
||||
LOG_LUA_LINE("Hooked chat command exceeded maximum references!");
|
||||
LOG_LUA_LINE("Hooked command exceeded maximum references!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* command = smlua_to_string(L, 1);
|
||||
if (command == NULL || strlen(command) == 0 || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook chat command: tried to hook invalid command");
|
||||
LOG_LUA_LINE("Hook command: tried to hook invalid command");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* description = smlua_to_string(L, 2);
|
||||
if (description == NULL || strlen(description) == 0 || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook chat command: tried to hook invalid description");
|
||||
LOG_LUA_LINE("Hook command: tried to hook invalid description");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
if (ref == -1) {
|
||||
LOG_LUA_LINE("Hook chat command: tried to hook undefined function '%s'", command);
|
||||
LOG_LUA_LINE("Hook command: tried to hook undefined function '%s'", command);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct LuaHookedChatCommand* hooked = &sHookedChatCommands[sHookedChatCommandsCount];
|
||||
struct LuaHookedCommand* hooked = &sHookedChatCommands[sHookedChatCommandsCount];
|
||||
hooked->command = strdup(command);
|
||||
hooked->description = strdup(description);
|
||||
hooked->reference = ref;
|
||||
hooked->mod = gLuaActiveMod;
|
||||
hooked->modFile = gLuaActiveModFile;
|
||||
hooked->isConsoleCommand = isConsoleCommand;
|
||||
|
||||
sHookedChatCommandsCount++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_hook_chat_command(lua_State* L) {
|
||||
return smlua_hook_command_internal(L, false);
|
||||
}
|
||||
|
||||
int smlua_hook_console_command(lua_State* L) {
|
||||
return smlua_hook_command_internal(L, true);
|
||||
}
|
||||
|
||||
int smlua_update_chat_command_description(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
|
||||
|
|
@ -1082,8 +1092,8 @@ int smlua_update_chat_command_description(lua_State* L) {
|
|||
}
|
||||
|
||||
for (int i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
|
||||
if (!strcmp(hook->command, command)) {
|
||||
struct LuaHookedCommand* hook = &sHookedChatCommands[i];
|
||||
if (!hook->isConsoleCommand && !strcmp(hook->command, command)) {
|
||||
if (hook->description) {
|
||||
free(hook->description);
|
||||
}
|
||||
|
|
@ -1096,19 +1106,50 @@ int smlua_update_chat_command_description(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int smlua_update_console_command_description(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
|
||||
|
||||
const char* command = smlua_to_string(L, 1);
|
||||
if (command == NULL || strlen(command) == 0 || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Update console command: tried to update invalid command");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* description = smlua_to_string(L, 2);
|
||||
if (description == NULL || strlen(description) == 0 || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Update console command: tried to update invalid description");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedCommand* hook = &sHookedChatCommands[i];
|
||||
if (hook->isConsoleCommand && !strcmp(hook->command, command)) {
|
||||
if (hook->description) {
|
||||
free(hook->description);
|
||||
}
|
||||
hook->description = strdup(description);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_LUA_LINE("Update console command: could not find command to update");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool smlua_call_chat_command_hook(char* command) {
|
||||
lua_State* L = gLuaState;
|
||||
if (L == NULL) { return false; }
|
||||
for (int i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
|
||||
struct LuaHookedCommand* hook = &sHookedChatCommands[i];
|
||||
// compare strings
|
||||
size_t commandLength = strlen(hook->command);
|
||||
for (size_t j = 0; j < commandLength; j++) {
|
||||
if (hook->command[j] != command[j + 1]) {
|
||||
goto NEXT_HOOK;
|
||||
}
|
||||
}
|
||||
if (strncmp(hook->command, command, commandLength) != 0) goto NEXT_HOOK;
|
||||
|
||||
char* params = &command[commandLength + 1];
|
||||
// make sure we aren't running a console command
|
||||
if (hook->isConsoleCommand && !gDjuiConsoleFocus) goto NEXT_HOOK;
|
||||
|
||||
char* params = &command[commandLength];
|
||||
if (*params != '\0' && *params != ' ') {
|
||||
goto NEXT_HOOK;
|
||||
}
|
||||
|
|
@ -1145,12 +1186,13 @@ NEXT_HOOK:;
|
|||
return false;
|
||||
}
|
||||
|
||||
void smlua_display_chat_commands(void) {
|
||||
void smlua_display_chat_commands(bool isConsole) {
|
||||
for (int i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
|
||||
struct LuaHookedCommand* hook = &sHookedChatCommands[i];
|
||||
if (!isConsole && hook->isConsoleCommand) continue;
|
||||
char msg[256] = { 0 };
|
||||
snprintf(msg, 256, "/%s %s", hook->command, hook->description);
|
||||
djui_chat_message_create(msg);
|
||||
command_message_create(msg, CONSOLE_MESSAGE_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1207,6 +1249,7 @@ char** smlua_get_chat_player_list(void) {
|
|||
return sortedPlayers;
|
||||
}
|
||||
|
||||
// this needs a rewrite, actually all these funcs needs a rewrite, actually, the whole autocomplete system needs a rewrite
|
||||
char** smlua_get_chat_maincommands_list(void) {
|
||||
#if defined(DEVELOPMENT)
|
||||
s32 defaultCmdsCount = 11;
|
||||
|
|
@ -1227,7 +1270,8 @@ char** smlua_get_chat_maincommands_list(void) {
|
|||
}
|
||||
char** commands = (char**) malloc((sHookedChatCommandsCount + defaultCmdsCountNew + 1) * sizeof(char*));
|
||||
for (s32 i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
|
||||
struct LuaHookedCommand* hook = &sHookedChatCommands[i];
|
||||
if (hook->isConsoleCommand) continue;
|
||||
commands[i] = strdup(hook->command);
|
||||
}
|
||||
for (s32 i = 0; i < defaultCmdsCount; i++) {
|
||||
|
|
@ -1251,7 +1295,7 @@ char** smlua_get_chat_subcommands_list(const char* maincommand) {
|
|||
}
|
||||
|
||||
for (s32 i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
|
||||
struct LuaHookedCommand* hook = &sHookedChatCommands[i];
|
||||
if (strcmp(hook->command, maincommand) == 0) {
|
||||
char* noColorsDesc = djui_text_get_uncolored_string(NULL, strlen(hook->description) + 1, hook->description);
|
||||
char* startSubcommands = strstr(noColorsDesc, "[");
|
||||
|
|
@ -1793,7 +1837,7 @@ void smlua_hook_replace_function_references(lua_State* L, int oldReference, int
|
|||
}
|
||||
|
||||
for (int i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedChatCommand* hooked = &sHookedChatCommands[i];
|
||||
struct LuaHookedCommand* hooked = &sHookedChatCommands[i];
|
||||
smlua_hook_replace_function_reference(L, &hooked->reference, oldReference, newReference);
|
||||
}
|
||||
|
||||
|
|
@ -1829,7 +1873,7 @@ void smlua_clear_hooks(void) {
|
|||
sHookedMarioActionsCount = 0;
|
||||
|
||||
for (int i = 0; i < sHookedChatCommandsCount; i++) {
|
||||
struct LuaHookedChatCommand* hooked = &sHookedChatCommands[i];
|
||||
struct LuaHookedCommand* hooked = &sHookedChatCommands[i];
|
||||
if (hooked->command != NULL) { free(hooked->command); }
|
||||
hooked->command = NULL;
|
||||
|
||||
|
|
@ -1896,6 +1940,7 @@ void smlua_bind_hooks(void) {
|
|||
smlua_bind_function(L, "hook_event", smlua_hook_event);
|
||||
smlua_bind_function(L, "hook_mario_action", smlua_hook_mario_action);
|
||||
smlua_bind_function(L, "hook_chat_command", smlua_hook_chat_command);
|
||||
smlua_bind_function(L, "hook_console_command", smlua_hook_console_command);
|
||||
smlua_bind_function(L, "hook_on_sync_table_change", smlua_hook_on_sync_table_change);
|
||||
smlua_bind_function(L, "hook_behavior", smlua_hook_behavior);
|
||||
smlua_bind_function(L, "hook_mod_menu_text", smlua_hook_mod_menu_text);
|
||||
|
|
@ -1904,6 +1949,7 @@ void smlua_bind_hooks(void) {
|
|||
smlua_bind_function(L, "hook_mod_menu_slider", smlua_hook_mod_menu_slider);
|
||||
smlua_bind_function(L, "hook_mod_menu_inputbox", smlua_hook_mod_menu_inputbox);
|
||||
smlua_bind_function(L, "update_chat_command_description", smlua_update_chat_command_description);
|
||||
smlua_bind_function(L, "update_console_command_description", smlua_update_console_command_description);
|
||||
smlua_bind_function(L, "update_mod_menu_element_name", smlua_update_mod_menu_element_name);
|
||||
smlua_bind_function(L, "update_mod_menu_element_checkbox", smlua_update_mod_menu_element_checkbox);
|
||||
smlua_bind_function(L, "update_mod_menu_element_slider", smlua_update_mod_menu_element_slider);
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ bool smlua_call_action_hook(enum LuaActionHookType hookType, struct MarioState*
|
|||
u32 smlua_get_action_interaction_type(struct MarioState* m);
|
||||
|
||||
bool smlua_call_chat_command_hook(char* command);
|
||||
void smlua_display_chat_commands(void);
|
||||
void smlua_display_chat_commands(bool isConsole);
|
||||
char** smlua_get_chat_player_list(void);
|
||||
char** smlua_get_chat_maincommands_list(void);
|
||||
char** smlua_get_chat_subcommands_list(const char* maincommand);
|
||||
|
|
|
|||
|
|
@ -743,33 +743,33 @@ const char* smlua_lnt_to_str(struct LSTNetworkType* lnt) {
|
|||
void smlua_dump_stack(void) {
|
||||
lua_State* L = gLuaState;
|
||||
int top = lua_gettop(L);
|
||||
printf("--------------\n");
|
||||
log_to_terminal("--------------\n");
|
||||
for (int i = 1; i <= top; i++) {
|
||||
printf("%d\t%s\t", i, luaL_typename(L, i));
|
||||
log_to_terminal("%d\t%s\t", i, luaL_typename(L, i));
|
||||
switch (lua_type(L, i)) {
|
||||
case LUA_TNUMBER:
|
||||
printf("%g\n", lua_tonumber(L, i));
|
||||
log_to_terminal("%g\n", lua_tonumber(L, i));
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
printf("%s\n", lua_tostring(L, i));
|
||||
log_to_terminal("%s\n", lua_tostring(L, i));
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
printf("%s\n", (lua_toboolean(L, i) ? "true" : "false"));
|
||||
log_to_terminal("%s\n", (lua_toboolean(L, i) ? "true" : "false"));
|
||||
break;
|
||||
case LUA_TNIL:
|
||||
printf("%s\n", "nil");
|
||||
log_to_terminal("%s\n", "nil");
|
||||
break;
|
||||
default:
|
||||
printf("%p\n", lua_topointer(L, i));
|
||||
log_to_terminal("%p\n", lua_topointer(L, i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("--------------\n");
|
||||
log_to_terminal("--------------\n");
|
||||
}
|
||||
|
||||
void smlua_dump_globals(void) {
|
||||
lua_State* L = gLuaState;
|
||||
printf("--------------\n");
|
||||
log_to_terminal("--------------\n");
|
||||
lua_pushglobaltable(L);
|
||||
|
||||
// table is in the stack at index 't'
|
||||
|
|
@ -777,12 +777,12 @@ void smlua_dump_globals(void) {
|
|||
while (lua_next(L, -2) != 0) {
|
||||
// uses 'key' (at index -2) and 'value' (at index -1)
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
printf("%s - %s\n",
|
||||
log_to_terminal("%s - %s\n",
|
||||
lua_tostring(L, -2),
|
||||
lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
else {
|
||||
printf("%s - %s\n",
|
||||
log_to_terminal("%s - %s\n",
|
||||
lua_typename(L, lua_type(L, -2)),
|
||||
lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
|
|
@ -790,23 +790,23 @@ void smlua_dump_globals(void) {
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1); // remove global table(-1)
|
||||
printf("--------------\n");
|
||||
log_to_terminal("--------------\n");
|
||||
}
|
||||
|
||||
void smlua_dump_table(int index) {
|
||||
lua_State* L = gLuaState;
|
||||
printf("--------------\n");
|
||||
log_to_terminal("--------------\n");
|
||||
|
||||
if (lua_getmetatable(L, index)) {
|
||||
lua_pushnil(L); // first key
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
printf("[meta] %s - %s\n",
|
||||
log_to_terminal("[meta] %s - %s\n",
|
||||
lua_tostring(L, -2),
|
||||
lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
else {
|
||||
printf("[meta] %s - %s\n",
|
||||
log_to_terminal("[meta] %s - %s\n",
|
||||
lua_typename(L, lua_type(L, -2)),
|
||||
lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
|
|
@ -820,19 +820,19 @@ void smlua_dump_table(int index) {
|
|||
while (lua_next(L, index) != 0) {
|
||||
// uses 'key' (at index -2) and 'value' (at index -1)
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
printf("%s - %s\n",
|
||||
log_to_terminal("%s - %s\n",
|
||||
lua_tostring(L, -2),
|
||||
lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
else {
|
||||
printf("%s - %s\n",
|
||||
log_to_terminal("%s - %s\n",
|
||||
lua_typename(L, lua_type(L, -2)),
|
||||
lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
// removes 'value'; keeps 'key' for next iteration
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
printf("--------------\n");
|
||||
log_to_terminal("--------------\n");
|
||||
}
|
||||
|
||||
void smlua_logline(void) {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@
|
|||
#include "pc/discord/discord.h"
|
||||
#endif
|
||||
|
||||
#include "pc/terminal.h"
|
||||
|
||||
#include "pc/mumble/mumble.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
|
@ -529,7 +531,7 @@ int main(int argc, char *argv[]) {
|
|||
} else
|
||||
#endif
|
||||
{
|
||||
printf("ERROR: could not find valid vanilla us sm64 rom in game's user folder\n");
|
||||
LOG_ERROR("Could not find valid vanilla us sm64 rom in game's user folder\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -602,6 +604,9 @@ int main(int argc, char *argv[]) {
|
|||
network_init(NT_NONE, false);
|
||||
}
|
||||
|
||||
// initialize terminal
|
||||
terminal_init();
|
||||
|
||||
// main loop
|
||||
while (true) {
|
||||
debug_context_reset();
|
||||
|
|
@ -611,6 +616,7 @@ int main(int argc, char *argv[]) {
|
|||
discord_update();
|
||||
#endif
|
||||
mumble_update();
|
||||
terminal_update();
|
||||
#ifdef DEBUG
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
|
|
|||
102
src/pc/terminal.c
Normal file
102
src/pc/terminal.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#include <stdio.h>
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include "linenoise/linenoise.h"
|
||||
#endif
|
||||
#include "djui/djui_console.h"
|
||||
#include "commands.h"
|
||||
#include "pc_main.h"
|
||||
#include "terminal.h"
|
||||
|
||||
#define TERMINAL_BUFFER_SIZE 1024
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
static struct linenoiseState sLinenoiseState;
|
||||
#endif
|
||||
static char sTerminalInput[TERMINAL_BUFFER_SIZE] = { 0 };
|
||||
static bool sTerminalInitialized = false;
|
||||
static bool sTerminalActive = false;
|
||||
|
||||
void log_to_terminal(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (sTerminalActive) linenoiseHide(&sLinenoiseState);
|
||||
#endif
|
||||
|
||||
vprintf(fmt, args);
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (sTerminalActive) linenoiseShow(&sLinenoiseState);
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void terminal_stop() {
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (!sTerminalInitialized) return;
|
||||
linenoiseEditStop(&sLinenoiseState);
|
||||
sTerminalActive = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void terminal_init() {
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
sTerminalActive = false;
|
||||
sTerminalInitialized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tcgetpgrp(STDIN_FILENO) != getpgrp()) {
|
||||
sTerminalActive = false;
|
||||
sTerminalInitialized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
linenoiseEditStart(&sLinenoiseState, -1, -1, sTerminalInput, sizeof(sTerminalInput), "> ");
|
||||
sTerminalInitialized = true;
|
||||
sTerminalActive = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void terminal_update() {
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (!sTerminalInitialized) return;
|
||||
struct timeval tv = {0L, 0L};
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
|
||||
if (select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv) <= 0) return;
|
||||
|
||||
char* input = linenoiseEditFeed(&sLinenoiseState);
|
||||
|
||||
if (input == NULL) {
|
||||
linenoiseEditStop(&sLinenoiseState);
|
||||
game_exit();
|
||||
} else if (input != linenoiseEditMore) {
|
||||
terminal_stop();
|
||||
|
||||
if (input[0] != '\0') {
|
||||
run_command(input);
|
||||
linenoiseHistoryAdd(input);
|
||||
}
|
||||
|
||||
free(input);
|
||||
|
||||
terminal_init();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void terminal_clear() {
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (!sTerminalInitialized) return;
|
||||
linenoiseClearScreen();
|
||||
#endif
|
||||
}
|
||||
9
src/pc/terminal.h
Normal file
9
src/pc/terminal.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include "src/pc/thread.h"
|
||||
|
||||
extern struct ThreadHandle gTerminalThread;
|
||||
|
||||
void log_to_terminal(const char* fmt, ...);
|
||||
void terminal_init();
|
||||
void terminal_update();
|
||||
void terminal_clear();
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include "pc/djui/djui.h"
|
||||
#include "pc/network/version.h"
|
||||
#include "pc/loading.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
#define URL "https://raw.githubusercontent.com/coop-deluxe/sm64coopdx/refs/heads/main/src/pc/network/version.h"
|
||||
#define VERSION_IDENTIFIER "#define SM64COOPDX_VERSION \""
|
||||
|
|
@ -73,7 +74,7 @@ void get_version_remote(void) {
|
|||
// initialize WinINet
|
||||
HINTERNET hInternet = InternetOpenA("sm64coopdx", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
|
||||
if (!hInternet) {
|
||||
printf("Failed to check for updates!\n");
|
||||
LOG_ERROR("Failed to check for updates!");
|
||||
InternetCloseHandle(hInternet);
|
||||
return;
|
||||
}
|
||||
|
|
@ -81,7 +82,7 @@ void get_version_remote(void) {
|
|||
// open the URL
|
||||
HINTERNET hUrl = InternetOpenUrlA(hInternet, URL, NULL, 0, INTERNET_FLAG_RELOAD, 0);
|
||||
if (!hUrl) {
|
||||
printf("Failed to check for updates!\n");
|
||||
LOG_ERROR("Failed to check for updates!");
|
||||
InternetCloseHandle(hInternet);
|
||||
InternetCloseHandle(hUrl);
|
||||
return;
|
||||
|
|
@ -95,7 +96,7 @@ void get_version_remote(void) {
|
|||
// read data from the URL, making room in the buffer for the null-terminator
|
||||
DWORD bytesRead;
|
||||
if (!InternetReadFile(hUrl, buffer, sizeof(buffer) - 1, &bytesRead)) {
|
||||
printf("Failed to check for updates!\n");
|
||||
LOG_ERROR("Failed to check for updates!");
|
||||
InternetCloseHandle(hInternet);
|
||||
InternetCloseHandle(hUrl);
|
||||
return;
|
||||
|
|
@ -112,7 +113,7 @@ void get_version_remote(void) {
|
|||
// initialize libcurl
|
||||
CURL *curl = curl_easy_init();
|
||||
if (!curl || curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
printf("Failed to check for updates!\n");
|
||||
LOG_ERROR("Failed to check for updates!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +127,7 @@ void get_version_remote(void) {
|
|||
// perform the request
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
printf("Failed to check for updates!\n");
|
||||
LOG_ERROR("Failed to check for updates!");
|
||||
curl_easy_cleanup(curl);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue