Added custom mod packets

This commit is contained in:
MysterD 2022-04-22 00:13:30 -07:00
parent ef7dc41560
commit bc7821a1e9
16 changed files with 391 additions and 96 deletions

View file

@ -159,6 +159,8 @@ manual_index_documentation = """
- [define_custom_obj_fields](#define_custom_obj_fields)
- [network_init_object](#network_init_object)
- [network_send_object](#network_send_object)
- [network_send_to](#network_send_to)
- [network_send](#network_send)
<br />
@ -236,6 +238,55 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
<br />
## [network_send_to](#network_send_to)
Sends a packet to a particular player (using their local index) containing whatever data you want.
`dataTable` can only contain strings, integers, numbers, booleans, and nil
The `reliable` field will ensure that the packet arrives, but should be used sparingly and only when missing a packet would cause a desync.
### Lua Example
`network_send_to(localPlayerIndex, reliable, { data1 = 'hello', data2 = 10})`
### Parameters
| Field | Type |
| ----- | ---- |
| localPlayerIndex | `integer` |
| reliable | `bool` |
| dataTable | `table` |
### C Prototype
`N/A`
[:arrow_up_small:](#)
<br />
## [network_send](#network_send)
Sends a packet to all players containing whatever data you want.
`dataTable` can only contain strings, integers, numbers, booleans, and nil
The `reliable` field will ensure that the packet arrives, but should be used sparingly and only when missing a packet would cause a desync.
### Lua Example
`network_send(reliable, { data1 = 'hello', data2 = 10})`
### Parameters
| Field | Type |
| ----- | ---- |
| reliable | `bool` |
| dataTable | `table` |
### C Prototype
`N/A`
[:arrow_up_small:](#)
<br />
"""
############################################################################

View file

@ -7852,7 +7852,10 @@ HOOK_ON_OBJECT_RENDER = 19
HOOK_ON_DEATH = 20
--- @type LuaHookedEventType
HOOK_MAX = 21
HOOK_ON_PACKET_RECEIVE = 21
--- @type LuaHookedEventType
HOOK_MAX = 22
--- @class ModelExtendedId

View file

@ -120,3 +120,17 @@ function network_send_object(object, reliable)
-- ...
end
--- @param reliable boolean
--- @param dataTable table
--- @return nil
function network_send(reliable, dataTable)
-- ...
end
--- @param toLocalIndex integer
--- @param reliable boolean
--- @param dataTable table
--- @return nil
function network_send_to(toLocalIndex, reliable, dataTable)
-- ...
end

View file

@ -2755,7 +2755,8 @@
| HOOK_ON_SET_CAMERA_MODE | 18 |
| HOOK_ON_OBJECT_RENDER | 19 |
| HOOK_ON_DEATH | 20 |
| HOOK_MAX | 21 |
| HOOK_ON_PACKET_RECEIVE | 21 |
| HOOK_MAX | 22 |
[:arrow_up_small:](#)

View file

@ -6,6 +6,8 @@
- [define_custom_obj_fields](#define_custom_obj_fields)
- [network_init_object](#network_init_object)
- [network_send_object](#network_send_object)
- [network_send_to](#network_send_to)
- [network_send](#network_send)
<br />
@ -1500,6 +1502,55 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
<br />
## [network_send_to](#network_send_to)
Sends a packet to a particular player (using their local index) containing whatever data you want.
`dataTable` can only contain strings, integers, numbers, booleans, and nil
The `reliable` field will ensure that the packet arrives, but should be used sparingly and only when missing a packet would cause a desync.
### Lua Example
`network_send_to(localPlayerIndex, reliable, { data1 = 'hello', data2 = 10})`
### Parameters
| Field | Type |
| ----- | ---- |
| localPlayerIndex | `integer` |
| reliable | `bool` |
| dataTable | `table` |
### C Prototype
`N/A`
[:arrow_up_small:](#)
<br />
## [network_send](#network_send)
Sends a packet to all players containing whatever data you want.
`dataTable` can only contain strings, integers, numbers, booleans, and nil
The `reliable` field will ensure that the packet arrives, but should be used sparingly and only when missing a packet would cause a desync.
### Lua Example
`network_send(reliable, { data1 = 'hello', data2 = 10})`
### Parameters
| Field | Type |
| ----- | ---- |
| reliable | `bool` |
| dataTable | `table` |
### C Prototype
`N/A`
[:arrow_up_small:](#)
<br />
---
# functions from behavior_actions.h

View file

@ -105,8 +105,9 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh
| HOOK_ON_PAUSE_EXIT | Called when the local player exits through the pause screen, return `false` to prevent the exit | `boolean` usedExitToCastle |
| HOOK_GET_STAR_COLLECTION_DIALOG | Called when the local player collects a star, return a [DialogId](constants.md#enum-DialogId) to show a message | None |
| HOOK_ON_SET_CAMERA_MODE | Called when the camera mode gets set, return `false` to prevent the camera mode from being set | [Camera](structs.md#Camera), `integer` mode, `integer` frames |
| HOOK_ON_OBJECT_RENDER | Called right before an object is rendered. **Note:** You must set the `hookRender` field of the object to a non-zero value | [Object](structs.md#Object) |
| HOOK_ON_DEATH | Called when the local player dies, return `false` to prevent normal death sequence | [MarioState](structs.md#MarioState) |
| HOOK_ON_OBJECT_RENDER | Called right before an object is rendered. **Note:** You must set the `hookRender` field of the object to a non-zero value | [Object](structs.md#Object) renderedObj |
| HOOK_ON_DEATH | Called when the local player dies, return `false` to prevent normal death sequence | [MarioState](structs.md#MarioState) localMario |
| HOOK_ON_PACKET_RECEIVE | Called when the mod receives a packet that used `network_send()` or `network_send_to()` | `table` dataTable |
### Parameters

View file

@ -2798,7 +2798,8 @@ char gSmluaConstants[] = ""
"HOOK_ON_SET_CAMERA_MODE = 18\n"
"HOOK_ON_OBJECT_RENDER = 19\n"
"HOOK_ON_DEATH = 20\n"
"HOOK_MAX = 21\n"
"HOOK_ON_PACKET_RECEIVE = 21\n"
"HOOK_MAX = 22\n"
"E_MODEL_NONE = 0\n"
"E_MODEL_MARIO = 1\n"
"E_MODEL_SMOKE = 2\n"

View file

@ -176,6 +176,16 @@ int smlua_func_network_send_object(lua_State* L) {
return 1;
}
int smlua_func_network_send(lua_State* L) {
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
network_send_lua_custom(true);
}
int smlua_func_network_send_to(lua_State* L) {
if (!smlua_functions_valid_param_count(L, 3)) { return 0; }
network_send_lua_custom(false);
}
//////////
// bind //
//////////
@ -191,4 +201,6 @@ void smlua_bind_functions(void) {
smlua_bind_function(L, "network_init_object", smlua_func_network_init_object);
smlua_bind_function(L, "network_send_object", smlua_func_network_send_object);
smlua_bind_function(L, "reset_level", smlua_func_reset_level);
smlua_bind_function(L, "network_send", smlua_func_network_send);
smlua_bind_function(L, "network_send_to", smlua_func_network_send_to);
}

View file

@ -1,4 +1,5 @@
#include "smlua.h"
#include "pc/mods/mod.h"
#include "src/game/object_list_processor.h"
#include "pc/djui/djui_chat_message.h"
#include "pc/crash_handler.h"
@ -454,6 +455,27 @@ void smlua_call_event_hooks_set_camera_mode_params(enum LuaHookedEventType hookT
}
}
void smlua_call_event_hooks_value_param(enum LuaHookedEventType hookType, int modIndex, int valueIndex) {
lua_State* L = gLuaState;
if (L == NULL) { return; }
struct LuaHookedEvent* hook = &sHookedEvents[hookType];
for (int i = 0; i < hook->count; i++) {
if (hook->mod[i]->index != modIndex) { continue; }
// push the callback onto the stack
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// push value
lua_pushvalue(L, valueIndex);
// call the callback
if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) {
LOG_LUA("Failed to call the callback: %u, %s", hookType, lua_tostring(L, -1));
smlua_logline();
continue;
}
}
}
////////////////////
// hooked actions //
////////////////////

View file

@ -29,6 +29,7 @@ enum LuaHookedEventType {
HOOK_ON_SET_CAMERA_MODE,
HOOK_ON_OBJECT_RENDER,
HOOK_ON_DEATH,
HOOK_ON_PACKET_RECEIVE,
HOOK_MAX,
};
@ -54,6 +55,7 @@ static char* LuaHookedEventTypeName[] = {
"HOOK_ON_SET_CAMERA_MODE",
"HOOK_ON_OBJECT_RENDER",
"HOOK_ON_DEATH",
"HOOK_ON_PACKET_RECEIVE",
"HOOK_MAX"
};
@ -70,6 +72,7 @@ void smlua_call_event_hooks_interact_params(enum LuaHookedEventType hookType, st
void smlua_call_event_hooks_object_param(enum LuaHookedEventType hookType, struct Object* obj);
bool smlua_call_event_hooks_ret_int(enum LuaHookedEventType hookType, s32* returnValue);
void smlua_call_event_hooks_set_camera_mode_params(enum LuaHookedEventType hookType, struct Camera *c, s16 mode, s16 frames, bool* returnValue);
void smlua_call_event_hooks_value_param(enum LuaHookedEventType hookType, int modIndex, int valueIndex);
enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior);
const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior);

View file

@ -260,6 +260,94 @@ struct LSTNetworkType smlua_to_lnt(lua_State* L, int index) {
///////////////////////////////////////////////////////////////////////////////////////////
bool packet_write_lnt(struct Packet* p, struct LSTNetworkType* lnt) {
u8 lntType = lnt->type;
packet_write(p, &lntType, sizeof(u8));
switch (lnt->type) {
case LST_NETWORK_TYPE_NUMBER: {
f64 number = lnt->value.number;
packet_write(p, &number, sizeof(f64));
return true;
}
case LST_NETWORK_TYPE_INTEGER: {
s64 integer = lnt->value.integer;
packet_write(p, &integer, sizeof(s64));
return true;
}
case LST_NETWORK_TYPE_BOOLEAN: {
packet_write(p, &lnt->value.boolean, sizeof(u8));
return true;
}
case LST_NETWORK_TYPE_STRING: {
u16 valueLength = strlen(lnt->value.string);
if (valueLength < 1 || valueLength > 256) {
LOG_ERROR("attempted to send lua variable with invalid string length: %u", valueLength);
return false;
}
packet_write(p, &valueLength, sizeof(u16));
packet_write(p, lnt->value.string, valueLength * sizeof(u8));
return true;
}
case LST_NETWORK_TYPE_NIL: {
// no-op
return true;
}
default:
break;
}
LOG_ERROR("attempted to send lua variable with invalid lnt type: %d", lnt->type);
return false;
}
bool packet_read_lnt(struct Packet* p, struct LSTNetworkType* lnt) {
packet_read(p, &lnt->type, sizeof(u8));
switch (lnt->type) {
case LST_NETWORK_TYPE_NUMBER:
packet_read(p, &lnt->value.number, sizeof(f64));
return true;
case LST_NETWORK_TYPE_INTEGER:
packet_read(p, &lnt->value.integer, sizeof(s64));
return true;
case LST_NETWORK_TYPE_BOOLEAN:
packet_read(p, &lnt->value.boolean, sizeof(u8));
return true;
case LST_NETWORK_TYPE_STRING: {
u16 valueLength = 0;
packet_read(p, &valueLength, sizeof(u16));
if (valueLength < 1 || valueLength > 256) {
LOG_ERROR("received lua variable with invalid value length: %d", valueLength);
return false;
}
lnt->value.string = calloc(valueLength + 1, sizeof(char));
packet_read(p, lnt->value.string, valueLength * sizeof(u8));
return true;
}
case LST_NETWORK_TYPE_NIL:
// no-op
return true;
default:
break;
}
LOG_ERROR("received lua variable with invalid type: %d", lnt->type);
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////
void smlua_push_object(lua_State* L, u16 lot, void* p) {
if (p == NULL) {
lua_pushnil(L);

View file

@ -3,6 +3,8 @@
extern u8 gSmLuaConvertSuccess;
typedef int LuaFunction;
struct Packet;
struct LSTNetworkType;
f32* smlua_get_vec3f_from_buffer(void);
s16* smlua_get_vec3s_from_buffer(void);
@ -19,6 +21,9 @@ void* smlua_to_cobject(lua_State* L, int index, u16 lot);
void* smlua_to_cpointer(lua_State* L, int index, u16 lvt);
struct LSTNetworkType smlua_to_lnt(lua_State* L, int index);
bool packet_write_lnt(struct Packet* p, struct LSTNetworkType* lnt);
bool packet_read_lnt(struct Packet* p, struct LSTNetworkType* lnt);
void smlua_push_object(lua_State* L, u16 lot, void* p);
void smlua_push_pointer(lua_State* L, u16 lvt, void* p);
void smlua_push_integer_field(int index, char* name, lua_Integer val);

View file

@ -92,7 +92,9 @@ void packet_process(struct Packet* p) {
case PACKET_NETWORK_PLAYERS_REQUEST: network_receive_network_players_request(p); break;
case PACKET_REQUEST_FAILED: network_receive_request_failed(p); break;
case PACKET_REQUEST_FAILED: network_receive_request_failed(p); break;
case PACKET_LUA_CUSTOM: network_receive_lua_custom(p); break;
// custom
case PACKET_CUSTOM: network_receive_custom(p); break;

View file

@ -69,6 +69,8 @@ enum PacketType {
PACKET_REQUEST_FAILED,
PACKET_LUA_CUSTOM,
///
PACKET_CUSTOM = 255,
};
@ -353,4 +355,8 @@ void network_receive_lua_sync_table(struct Packet* p);
void network_send_request_failed(struct NetworkPlayer* toNp, u8 requestType);
void network_receive_request_failed(struct Packet* p);
// packet_lua_custom.c
void network_send_lua_custom(bool broadcast);
void network_receive_lua_custom(struct Packet* p);
#endif

View file

@ -0,0 +1,125 @@
#include <stdio.h>
#include "../network.h"
#include "pc/mods/mod.h"
#include "pc/lua/smlua.h"
#include "pc/lua/smlua_utils.h"
#include "pc/debuglog.h"
void network_send_lua_custom(bool broadcast) {
LOG_INFO("Sending lua custom packet");
lua_State* L = gLuaState;
u16 zero = 0;
s32 paramIndex = 1;
// figure out mod index
if (gLuaActiveMod == NULL) {
LOG_LUA("Could not figure out the current active mod!");
smlua_logline();
return;
}
u16 modIndex = gLuaActiveMod->index;
// get local index
s32 toLocalIndex = 0;
if (!broadcast) {
s32 toLocalIndex = smlua_to_integer(L, paramIndex++);
if (toLocalIndex <= 0 || toLocalIndex >= MAX_PLAYERS) {
LOG_LUA("Tried to send packet to invalid local index: %d", toLocalIndex)
smlua_logline();
return;
}
if (!gSmLuaConvertSuccess) { return; }
}
// get reliability
bool reliability = smlua_to_boolean(L, paramIndex++);
if (!gSmLuaConvertSuccess) { return; }
// write packet header
struct Packet p = { 0 };
packet_init(&p, PACKET_LUA_CUSTOM, reliability, PLMT_NONE);
packet_write(&p, &modIndex, sizeof(u16));
u8* keyCount = &p.buffer[p.cursor];
packet_write(&p, &zero, sizeof(u8));
// make sure value passed in is a table
s32 tableIndex = paramIndex;
if (lua_type(L, tableIndex) != LUA_TTABLE) {
LOG_LUA("Tried to send a packet with a non-table");
smlua_logline();
return;
}
// iterate table
s32 iterateIndex = lua_gettop(L);
lua_pushnil(L); // first key
while (lua_next(L, iterateIndex) != 0) {
// convert and write key
struct LSTNetworkType lntKey = smlua_to_lnt(L, -2);
if (!gSmLuaConvertSuccess) {
LOG_LUA("Failed to convert key to LNT (tx)");
smlua_logline();
return;
}
if (!packet_write_lnt(&p, &lntKey)) {
return;
}
// convert and write value
struct LSTNetworkType lntValue = smlua_to_lnt(L, -1);
if (!gSmLuaConvertSuccess) {
LOG_LUA("Failed to convert value to LNT (tx)");
smlua_logline();
return;
}
if (!packet_write_lnt(&p, &lntValue)) {
return;
}
// increment key count
*keyCount = *keyCount + 1;
lua_pop(L, 1); // pop value
}
lua_pop(L, 1); // pop key
// send packet
if (broadcast) {
network_send(&p);
} else {
network_send_to(toLocalIndex, &p);
}
}
void network_receive_lua_custom(struct Packet* p) {
LOG_INFO("Receiving lua custom packet");
lua_State* L = gLuaState;
u16 modIndex = 0;
u8 keyCount = 0;
packet_read(p, &modIndex, sizeof(u16));
packet_read(p, &keyCount, sizeof(u8));
lua_newtable(L);
s32 tableIndex = lua_gettop(L);
for(u16 i = 0; i < keyCount; i++) {
struct LSTNetworkType lntKey = { 0 };
if (!packet_read_lnt(p, &lntKey)) {
LOG_LUA("Failed to convert key to LNT (rx)");
smlua_logline();
return;
}
smlua_push_lnt(&lntKey);
struct LSTNetworkType lntValue = { 0 };
if (!packet_read_lnt(p, &lntValue)) {
LOG_LUA("Failed to convert value to LNT (rx)");
smlua_logline();
return;
}
smlua_push_lnt(&lntValue);
lua_settable(L, -3);
}
smlua_call_event_hooks_value_param(HOOK_ON_PACKET_RECEIVE, modIndex, tableIndex);
lua_pop(L, 1); // pop table
}

View file

@ -20,96 +20,6 @@ void network_receive_lua_sync_table_request(struct Packet* p) {
LOG_INFO("received lua sync table request");
}
/////////////////////////////////////////////////////////////
static bool packet_write_lnt(struct Packet* p, struct LSTNetworkType* lnt) {
u8 lntType = lnt->type;
packet_write(p, &lntType, sizeof(u8));
switch (lnt->type) {
case LST_NETWORK_TYPE_NUMBER: {
f64 number = lnt->value.number;
packet_write(p, &number, sizeof(f64));
return true;
}
case LST_NETWORK_TYPE_INTEGER: {
s64 integer = lnt->value.integer;
packet_write(p, &integer, sizeof(s64));
return true;
}
case LST_NETWORK_TYPE_BOOLEAN: {
packet_write(p, &lnt->value.boolean, sizeof(u8));
return true;
}
case LST_NETWORK_TYPE_STRING: {
u16 valueLength = strlen(lnt->value.string);
if (valueLength < 1 || valueLength > 256) {
LOG_ERROR("attempted to send lua sync table with invalid string length: %u", valueLength);
return false;
}
packet_write(p, &valueLength, sizeof(u16));
packet_write(p, lnt->value.string, valueLength * sizeof(u8));
return true;
}
case LST_NETWORK_TYPE_NIL: {
// no-op
return true;
}
default:
break;
}
LOG_ERROR("attempted to send lua sync table with invalid lnt type: %d", lnt->type);
return false;
}
static bool packet_read_lnt(struct Packet* p, struct LSTNetworkType* lnt) {
packet_read(p, &lnt->type, sizeof(u8));
switch (lnt->type) {
case LST_NETWORK_TYPE_NUMBER:
packet_read(p, &lnt->value.number, sizeof(f64));
return true;
case LST_NETWORK_TYPE_INTEGER:
packet_read(p, &lnt->value.integer, sizeof(s64));
return true;
case LST_NETWORK_TYPE_BOOLEAN:
packet_read(p, &lnt->value.boolean, sizeof(u8));
return true;
case LST_NETWORK_TYPE_STRING: {
u16 valueLength = 0;
packet_read(p, &valueLength, sizeof(u16));
if (valueLength < 1 || valueLength > 256) {
LOG_ERROR("received lua sync table with invalid value length: %d", valueLength);
return false;
}
lnt->value.string = calloc(valueLength + 1, sizeof(char));
packet_read(p, lnt->value.string, valueLength * sizeof(u8));
return true;
}
case LST_NETWORK_TYPE_NIL:
// no-op
return true;
default:
break;
}
LOG_ERROR("received lua sync table with invalid type: %d", lnt->type);
return false;
}
/////////////////////////////////////////////////////////////
void network_send_lua_sync_table(u8 toLocalIndex, u64 seq, u16 modRemoteIndex, u16 lntKeyCount, struct LSTNetworkType* lntKeys, struct LSTNetworkType* lntValue) {
if (gLuaState == NULL) { return; }