mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 13:35:12 +00:00
Merge branch 'coopnet' into coop
This commit is contained in:
commit
98c78a9470
105 changed files with 2452 additions and 1614 deletions
65
Makefile
65
Makefile
|
@ -48,10 +48,10 @@ EXT_OPTIONS_MENU ?= 1
|
|||
TEXTSAVES ?= 0
|
||||
# Load resources from external files
|
||||
EXTERNAL_DATA ?= 0
|
||||
# Enable Discord Rich Presence (outdated, no longer supported)
|
||||
DISCORDRPC ?= 0
|
||||
# Enable Discord Game SDK (used for Discord server hosting)
|
||||
# Enable Discord Game SDK (used for Discord invites)
|
||||
DISCORD_SDK ?= 1
|
||||
# Enable CoopNet SDK (used for CoopNet server hosting)
|
||||
COOPNET ?= 1
|
||||
# Enable docker build workarounds
|
||||
DOCKERBUILD ?= 0
|
||||
# Sets your optimization level for building.
|
||||
|
@ -526,14 +526,10 @@ SRC_DIRS := src src/engine src/game src/audio src/bass_audio src/menu src/buffer
|
|||
BIN_DIRS := bin bin/$(VERSION)
|
||||
|
||||
# PC files
|
||||
SRC_DIRS += src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes src/pc/mods src/pc/network src/pc/network/packets src/pc/network/socket src/pc/utils src/pc/utils/miniz src/pc/djui src/pc/lua src/pc/lua/utils
|
||||
|
||||
#ifeq ($(DISCORDRPC),1)
|
||||
# SRC_DIRS += src/pc/discord
|
||||
#endif
|
||||
SRC_DIRS += src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes src/pc/mods src/pc/network src/pc/network/packets src/pc/network/socket src/pc/network/coopnet src/pc/utils src/pc/utils/miniz src/pc/djui src/pc/lua src/pc/lua/utils
|
||||
|
||||
ifeq ($(DISCORD_SDK),1)
|
||||
SRC_DIRS += src/pc/network/discord
|
||||
SRC_DIRS += src/pc/discord
|
||||
endif
|
||||
|
||||
ULTRA_SRC_DIRS := lib/src lib/src/math lib/asm lib/data
|
||||
|
@ -605,18 +601,8 @@ ULTRA_O_FILES := $(foreach file,$(ULTRA_S_FILES),$(BUILD_DIR)/$(file:.s=.o)) \
|
|||
GODDARD_O_FILES := $(foreach file,$(GODDARD_C_FILES),$(BUILD_DIR)/$(file:.c=.o))
|
||||
|
||||
RPC_LIBS :=
|
||||
#ifeq ($(DISCORDRPC),1)
|
||||
# ifeq ($(WINDOWS_BUILD),1)
|
||||
# RPC_LIBS := lib/discord/libdiscord-rpc.dll
|
||||
# else ifeq ($(OSX_BUILD),1)
|
||||
# # needs testing
|
||||
# RPC_LIBS := lib/discord/libdiscord-rpc.dylib
|
||||
# else
|
||||
# RPC_LIBS := lib/discord/libdiscord-rpc.so
|
||||
# endif
|
||||
#endif
|
||||
|
||||
DISCORD_SDK_LIBS :=
|
||||
|
||||
ifeq ($(DISCORD_SDK), 1)
|
||||
ifeq ($(WINDOWS_BUILD),1)
|
||||
ifeq ($(TARGET_BITS), 32)
|
||||
|
@ -756,7 +742,6 @@ else
|
|||
CP := cp
|
||||
endif
|
||||
|
||||
#ifeq ($(DISCORDRPC),1)
|
||||
ifeq ($(DISCORD_SDK),1)
|
||||
LD := $(CXX)
|
||||
else ifeq ($(WINDOWS_BUILD),1)
|
||||
|
@ -786,7 +771,7 @@ INCLUDE_DIRS := include $(BUILD_DIR) $(BUILD_DIR)/include src .
|
|||
ifeq ($(TARGET_N64),1)
|
||||
INCLUDE_DIRS += include/libc
|
||||
else
|
||||
INCLUDE_DIRS += sound lib/lua/include $(EXTRA_INCLUDES)
|
||||
INCLUDE_DIRS += sound lib/lua/include lib/coopnet/include $(EXTRA_INCLUDES)
|
||||
endif
|
||||
|
||||
# Connfigure backend flags
|
||||
|
@ -921,9 +906,6 @@ else ifeq ($(OSX_BUILD),1)
|
|||
LDFLAGS := -lm $(BACKEND_LDFLAGS) -lpthread
|
||||
else
|
||||
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -no-pie -lpthread
|
||||
# ifeq ($(DISCORDRPC),1)
|
||||
# LDFLAGS += -ldl -Wl,-rpath .
|
||||
# endif
|
||||
endif
|
||||
|
||||
# icon
|
||||
|
@ -981,6 +963,27 @@ else
|
|||
LDFLAGS += -Llib/lua/linux -l:liblua53.a -ldl
|
||||
endif
|
||||
|
||||
# coopnet
|
||||
ifeq ($(COOPNET),1)
|
||||
ifeq ($(WINDOWS_BUILD),1)
|
||||
ifeq ($(TARGET_BITS), 32)
|
||||
LDFLAGS += -Llib/coopnet/win32 -l:libcoopnet.a -l:libjuice.a -lbcrypt -lws2_32
|
||||
else
|
||||
LDFLAGS += -Llib/coopnet/win64 -l:libcoopnet.a -l:libjuice.a -lbcrypt -lws2_32
|
||||
endif
|
||||
else ifeq ($(OSX_BUILD),1)
|
||||
LDFLAGS += -L./lib/coopnet/mac/ -l coopnet
|
||||
else ifeq ($(TARGET_RPI),1)
|
||||
ifneq (,$(findstring aarch64,$(machine)))
|
||||
LDFLAGS += -Llib/coopnet/linux -l:libcoopnet-arm64.a -l:libjuice.a
|
||||
else
|
||||
LDFLAGS += -Llib/coopnet/linux -l:libcoopnet-arm.a -l:libjuice.a
|
||||
endif
|
||||
else
|
||||
LDFLAGS += -Llib/coopnet/linux -l:libcoopnet.a -l:libjuice.a
|
||||
endif
|
||||
endif
|
||||
|
||||
# Network/Discord/Bass (ugh, needs cleanup)
|
||||
ifeq ($(WINDOWS_BUILD),1)
|
||||
LDFLAGS += -L"ws2_32" -lwsock32
|
||||
|
@ -1057,18 +1060,18 @@ endif
|
|||
CFLAGS += -DNODRAWINGDISTANCE
|
||||
#endif
|
||||
|
||||
# Check for Discord Rich Presence option
|
||||
#ifeq ($(DISCORDRPC),1)
|
||||
# CC_CHECK_CFLAGS += -DDISCORDRPC
|
||||
# CFLAGS += -DDISCORDRPC
|
||||
#endif
|
||||
|
||||
# Check for Discord SDK option
|
||||
ifeq ($(DISCORD_SDK),1)
|
||||
CC_CHECK_CFLAGS += -DDISCORD_SDK
|
||||
CFLAGS += -DDISCORD_SDK
|
||||
endif
|
||||
|
||||
# Check for COOPNET option
|
||||
ifeq ($(COOPNET),1)
|
||||
CC_CHECK_CFLAGS += -DCOOPNET
|
||||
CFLAGS += -DCOOPNET
|
||||
endif
|
||||
|
||||
# Check for development option
|
||||
ifeq ($(DEVELOPMENT),1)
|
||||
CC_CHECK_CFLAGS += -DDEVELOPMENT
|
||||
|
|
|
@ -47,6 +47,7 @@ in_files = [
|
|||
"src/pc/lua/utils/smlua_text_utils.h",
|
||||
"src/pc/lua/utils/smlua_audio_utils.h",
|
||||
"src/pc/lua/utils/smlua_level_utils.h",
|
||||
"src/pc/lua/utils/smlua_deprecated.h",
|
||||
"src/game/object_helpers.c",
|
||||
"src/game/obj_behaviors.c",
|
||||
"src/game/obj_behaviors_2.c",
|
||||
|
@ -106,6 +107,10 @@ override_disallowed_functions = {
|
|||
"src/pc/network/lag_compensation.h": [ "lag_compensation_clear", "lag_compensation_store" ],
|
||||
}
|
||||
|
||||
override_hide_functions = {
|
||||
"smlua_deprecated.h" : [ ".*" ],
|
||||
}
|
||||
|
||||
lua_function_params = {
|
||||
"src/pc/lua/utils/smlua_obj_utils.h::spawn_object_sync::objSetupFunction": [ "struct Object*" ]
|
||||
}
|
||||
|
@ -763,6 +768,16 @@ def process_files():
|
|||
|
||||
############################################################################
|
||||
|
||||
def doc_should_document(fname, identifier):
|
||||
if fname in override_hide_functions:
|
||||
found_match = False
|
||||
for pattern in override_hide_functions[fname]:
|
||||
if re.search(pattern, identifier) != None:
|
||||
found_match = True
|
||||
break
|
||||
return not found_match
|
||||
return True
|
||||
|
||||
def doc_page_link(page_num):
|
||||
if page_num == 1:
|
||||
return 'functions.md'
|
||||
|
@ -779,6 +794,9 @@ def doc_function_index(processed_files):
|
|||
for function in processed_file['functions']:
|
||||
if not function['implemented']:
|
||||
continue
|
||||
if not doc_should_document(processed_file['filename'], function['identifier']):
|
||||
continue
|
||||
|
||||
s += ' - [%s](%s#%s)\n' % (function['identifier'], doc_page_link(page_num), function['identifier'])
|
||||
s += '\n<br />\n\n'
|
||||
|
||||
|
@ -805,10 +823,13 @@ def doc_lua_func_param(param):
|
|||
s += ')'
|
||||
return s
|
||||
|
||||
def doc_function(function):
|
||||
def doc_function(fname, function):
|
||||
if not function['implemented']:
|
||||
return ''
|
||||
|
||||
if not doc_should_document(fname, function['identifier']):
|
||||
return ''
|
||||
|
||||
fid = function['identifier']
|
||||
s = '\n## [%s](#%s)\n' % (fid, fid)
|
||||
|
||||
|
@ -860,10 +881,10 @@ def doc_function(function):
|
|||
|
||||
return s
|
||||
|
||||
def doc_functions(functions):
|
||||
def doc_functions(fname, functions):
|
||||
s = ''
|
||||
for function in functions:
|
||||
s += doc_function(function)
|
||||
s += doc_function(fname, function)
|
||||
return s
|
||||
|
||||
def doc_files(processed_files):
|
||||
|
@ -879,7 +900,7 @@ def doc_files(processed_files):
|
|||
for processed_file in processed_files:
|
||||
s_file = '\n---'
|
||||
s_file += '\n# functions from %s\n\n<br />\n\n' % processed_file['filename']
|
||||
s_file += doc_functions(processed_file['functions'])
|
||||
s_file += doc_functions(processed_file['filename'], processed_file['functions'])
|
||||
|
||||
if len(s) + len(s_file) + extra_space > page_len_limit:
|
||||
s += '---\n\n$[FUNCTION_NAV_HERE]\n\n'
|
||||
|
|
|
@ -4727,7 +4727,10 @@ SYNC_DISTANCE_INFINITE = 0
|
|||
NS_SOCKET = 0
|
||||
|
||||
--- @type NetworkSystemType
|
||||
NS_DISCORD = 1
|
||||
NS_COOPNET = 1
|
||||
|
||||
--- @type NetworkSystemType
|
||||
NS_MAX = 2
|
||||
|
||||
--- @class PlayerInteractions
|
||||
|
||||
|
@ -4744,7 +4747,7 @@ PLAYER_INTERACTIONS_PVP = 2
|
|||
MAX_RX_SEQ_IDS = 64
|
||||
|
||||
--- @type integer
|
||||
NETWORK_PLAYER_PING_TIMEOUT = 1
|
||||
NETWORK_PLAYER_PING_TIMEOUT = 3
|
||||
|
||||
--- @type integer
|
||||
NETWORK_PLAYER_TIMEOUT = 10
|
||||
|
@ -11522,13 +11525,13 @@ MAX_LOCAL_VERSION_LENGTH = 12
|
|||
MAX_VERSION_LENGTH = 10
|
||||
|
||||
--- @type integer
|
||||
MINOR_VERSION_NUMBER = 1
|
||||
MINOR_VERSION_NUMBER = 0
|
||||
|
||||
--- @type integer
|
||||
PATCH_VERSION_NUMBER = 0
|
||||
|
||||
--- @type integer
|
||||
VERSION_NUMBER = 33
|
||||
VERSION_NUMBER = 34
|
||||
|
||||
--- @type string
|
||||
VERSION_TEXT = "beta"
|
||||
|
|
|
@ -5639,12 +5639,6 @@ function network_player_set_description(np, description, r, g, b, a)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param localIndex integer
|
||||
--- @return string
|
||||
function network_discord_id_from_local_index(localIndex)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param localIndex integer
|
||||
--- @return string
|
||||
function network_get_player_text_color_string(localIndex)
|
||||
|
@ -8015,6 +8009,12 @@ function smlua_collision_util_get(name)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param localIndex integer
|
||||
--- @return string
|
||||
function network_discord_id_from_local_index(localIndex)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param scriptEntryName string
|
||||
--- @param courseNum integer
|
||||
--- @param fullName string
|
||||
|
|
|
@ -1721,6 +1721,7 @@
|
|||
--- @field public enablePlayerList integer
|
||||
--- @field public enablePlayersInLevelDisplay integer
|
||||
--- @field public headlessServer integer
|
||||
--- @field public maxPlayers integer
|
||||
--- @field public playerInteractions PlayerInteractions
|
||||
--- @field public playerKnockbackStrength integer
|
||||
--- @field public shareLives integer
|
||||
|
|
|
@ -1690,7 +1690,8 @@
|
|||
| Identifier | Value |
|
||||
| :--------- | :---- |
|
||||
| NS_SOCKET | 0 |
|
||||
| NS_DISCORD | 1 |
|
||||
| NS_COOPNET | 1 |
|
||||
| NS_MAX | 2 |
|
||||
|
||||
### [enum PlayerInteractions](#PlayerInteractions)
|
||||
| Identifier | Value |
|
||||
|
|
|
@ -8265,26 +8265,6 @@
|
|||
<br />
|
||||
|
||||
|
||||
## [network_discord_id_from_local_index](#network_discord_id_from_local_index)
|
||||
|
||||
### Lua Example
|
||||
`local stringValue = network_discord_id_from_local_index(localIndex)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| localIndex | `integer` |
|
||||
|
||||
### Returns
|
||||
- `string`
|
||||
|
||||
### C Prototype
|
||||
`char* network_discord_id_from_local_index(u8 localIndex);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [network_get_player_text_color_string](#network_get_player_text_color_string)
|
||||
|
||||
### Lua Example
|
||||
|
|
|
@ -7251,6 +7251,12 @@
|
|||
|
||||
<br />
|
||||
|
||||
---
|
||||
# functions from smlua_deprecated.h
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
---
|
||||
# functions from smlua_level_utils.h
|
||||
|
||||
|
|
|
@ -1096,7 +1096,6 @@
|
|||
<br />
|
||||
|
||||
- network_utils.h
|
||||
- [network_discord_id_from_local_index](functions-3.md#network_discord_id_from_local_index)
|
||||
- [network_get_player_text_color_string](functions-3.md#network_get_player_text_color_string)
|
||||
- [network_global_index_from_local](functions-3.md#network_global_index_from_local)
|
||||
- [network_is_moderator](functions-3.md#network_is_moderator)
|
||||
|
@ -1490,6 +1489,10 @@
|
|||
|
||||
<br />
|
||||
|
||||
- smlua_deprecated.h
|
||||
|
||||
<br />
|
||||
|
||||
- smlua_level_utils.h
|
||||
- [level_register](functions-4.md#level_register)
|
||||
- [smlua_level_util_get_info](functions-4.md#smlua_level_util_get_info)
|
||||
|
|
|
@ -2181,6 +2181,7 @@
|
|||
| enablePlayerList | `integer` | |
|
||||
| enablePlayersInLevelDisplay | `integer` | |
|
||||
| headlessServer | `integer` | |
|
||||
| maxPlayers | `integer` | |
|
||||
| playerInteractions | [enum PlayerInteractions](constants.md#enum-PlayerInteractions) | |
|
||||
| playerKnockbackStrength | `integer` | |
|
||||
| shareLives | `integer` | |
|
||||
|
|
|
@ -19,6 +19,16 @@ IMPORT_MOD_SUCCESS = "\\#a0ffa0\\Imported mod\n\\#c8c8c8\\'@'"
|
|||
IMPORT_DYNOS_SUCCESS = "\\#a0ffa0\\Imported DynOS pack\n\\#c8c8c8\\'@'"
|
||||
IMPORT_FAIL = "\\#ffa0a0\\Failed to import\n\\#c8c8c8\\'@'"
|
||||
IMPORT_FAIL_INGAME = "\\#ffa0a0\\Can not import while in-game"
|
||||
COOPNET_CONNECTION_FAILED = "\\#ffa0a0\\Could not connect to CoopNet!"
|
||||
COOPNET_DISCONNECTED = "\\#ffa0a0\\Lost connection to CoopNet!"
|
||||
LOBBY_NOT_FOUND = "\\#ffa0a0\\The lobby no longer exists!"
|
||||
LOBBY_JOIN_FULL = "\\#ffa0a0\\The lobby is full!"
|
||||
LOBBY_JOIN_FAILED = "\\#ffa0a0\\Failed to join the lobby!"
|
||||
LOBBY_PASSWORD_INCORRECT = "\\#ffa0a0\\Entered the wrong lobby password!"
|
||||
COOPNET_VERSION = "\\#ffa0a0\\Your version is no longer compatible with CoopNet. Update the game!"
|
||||
PEER_FAILED = "\\#ffa0a0\\Failed to connect to player '@'"
|
||||
UNKNOWN = "unknown"
|
||||
LOBBY_HOST = "the lobby's host"
|
||||
|
||||
[CHAT]
|
||||
KICKING = "Kicking '@'!"
|
||||
|
@ -177,8 +187,10 @@ SERVER_TITLE = "SERVER"
|
|||
HOST_TITLE = "HOST"
|
||||
DISCORD = "Discord"
|
||||
DIRECT_CONNECTION = "Direct Connection"
|
||||
COOPNET = "CoopNet"
|
||||
NETWORK_SYSTEM = "Network system"
|
||||
PORT = "Port"
|
||||
PASSWORD = "Password"
|
||||
SAVE_SLOT = "Save Slot"
|
||||
SETTINGS = "Settings"
|
||||
MODS = "Mods"
|
||||
|
@ -194,6 +206,9 @@ JOIN_TITLE = "JOIN"
|
|||
JOIN_DISCORD = "To join a \\#d0d0ff\\Discord\\#c8c8c8\\ lobby:\n\nKeep the game open and click the join button on the invite.\n\nIf the invite says that the game has ended, click the name of the person that sent the invite to refresh it."
|
||||
JOIN_SOCKET = "Enter \\#d0d0ff\\direct connection\\#c8c8c8\\ IP and port:"
|
||||
JOIN = "Join"
|
||||
PUBLIC_LOBBIES = "Public Lobbies"
|
||||
PRIVATE_LOBBIES = "Private Lobbies"
|
||||
DIRECT = "Direct Connection"
|
||||
|
||||
[MAIN]
|
||||
QUIT_TITLE = "QUIT"
|
||||
|
@ -321,3 +336,12 @@ ENV_VOLUME = "Env Volume"
|
|||
|
||||
[LANGUAGE]
|
||||
LANGUAGE = "LANGUAGE"
|
||||
|
||||
[LOBBIES]
|
||||
PUBLIC_LOBBIES = "PUBLIC LOBBIES"
|
||||
PRIVATE_LOBBIES = "PRIVATE LOBBIES"
|
||||
REFRESH = "Refresh"
|
||||
REFRESHING = "Refreshing..."
|
||||
ENTER_PASSWORD = "Enter the private lobby's password:"
|
||||
SEARCH = "Search"
|
||||
NONE_FOUND = "No lobbies were found."
|
||||
|
|
|
@ -177,6 +177,7 @@ SERVER_TITLE = "SERVEUR"
|
|||
HOST_TITLE = "HÉBERGER"
|
||||
DISCORD = "Discord"
|
||||
DIRECT_CONNECTION = "Connexion Directe"
|
||||
COOPNET = "CoopNet"
|
||||
NETWORK_SYSTEM = "Mode d'hébergement"
|
||||
PORT = "Port"
|
||||
SAVE_SLOT = "Sauvegarde"
|
||||
|
|
|
@ -177,6 +177,7 @@ SERVER_TITLE = "SERVER"
|
|||
HOST_TITLE = "VERANSTALTEN"
|
||||
DISCORD = "Discord"
|
||||
DIRECT_CONNECTION = "Direkte Verbindung"
|
||||
COOPNET = "CoopNet"
|
||||
NETWORK_SYSTEM = "Netzwerk-System"
|
||||
PORT = "Port"
|
||||
SAVE_SLOT = "Save Slot"
|
||||
|
|
320
lang/Italian.ini
Normal file
320
lang/Italian.ini
Normal file
|
@ -0,0 +1,320 @@
|
|||
[NOTIF]
|
||||
CONNECTED = "@ si è connesso"
|
||||
DISCONNECTED = "@ si è disconnesso"
|
||||
LEFT_THIS_LEVEL = "@ ha lasciato il livello"
|
||||
ENTERED_THIS_LEVEL = "@ è entrato nel livello"
|
||||
ENTERED = "@ è entrato in\n#"
|
||||
SERVER_CLOSED = "\\#ffa0a0\\Disconnesso:\\#dcdcdc\\ server chiuso"
|
||||
DISCORD_ERROR = "Errore: Discord ha avuto un errore\nPer risolverlo, prova a: \n1. Chiudere il gioco.\n2. Riavviare Discord.\n3. Avviare il gioco."
|
||||
DISCORD_DETECT = "\\#ffa0a0\\Errore:\\#c8c8c8\\ impossibile individuare Discord.\n\\#a0a0a0\\Prova a chiudere il gioco, riavviare Discord, e poi riaprire il gioco."
|
||||
DISCONNECT_FULL = "\\#ffa0a0\\Disconnesso:\\#c8c8c8\\ il server è pieno."
|
||||
DISCONNECT_KICK = "\\#ffa0a0\\Disconnesso:\\#c8c8c8\\ sei stato espulso."
|
||||
DISCONNECT_BAN = "\\#ffa0a0\\Disconnesso:\\#c8c8c8\\ sei stato bandito."
|
||||
DISCONNECT_REJOIN = "\\#ffa0a0\\Disconnesso:\\#c8c8c8\\ ricollegandoti..."
|
||||
DISCONNECT_CLOSED = "\\#ffa0a0\\Disconnesso:\\#c8c8c8\\ l'host ha interroto la connessione."
|
||||
DISCONNECT_BIG_MOD = "Il server ha una mod troppo pesante.\nDisconnessione."
|
||||
DIED = "@ è morto"
|
||||
DEBUG_FLY = "@ è entrato nello stato di debug di volo libero"
|
||||
IMPORT_MOD_SUCCESS = "\\#a0ffa0\\importata la mod\n\\#c8c8c8\\'@'"
|
||||
IMPORT_DYNOS_SUCCESS = "\\#a0ffa0\\Importato il pacchetto DynOS\n\\#c8c8c8\\'@'"
|
||||
IMPORT_FAIL = "\\#ffa0a0\\Impossibile importare\n\\#c8c8c8\\'@'"
|
||||
IMPORT_FAIL_INGAME = "\\#ffa0a0\\Impossibile importare durante la partita"
|
||||
|
||||
[CHAT]
|
||||
KICKING = "Espulso '@'!"
|
||||
BANNING = "Bandito '@'!"
|
||||
SERVER_ONLY = "Solo il server può usare questo comando."
|
||||
PERM_BANNING = "Bandito permanentemente '@'!"
|
||||
ADD_MODERATOR = "Aggiunto '@' tra i Moderatori!"
|
||||
PLAYERS = "Giocatori"
|
||||
NO_PERMS = "Non hai il permesso di usare questo comando."
|
||||
PLAYER_NOT_FOUND = "Impossibile trovare il giocatore."
|
||||
SELF_KICK = "Non puoi espellere te stesso."
|
||||
SELF_BAN = "Non puoi bandire te stesso."
|
||||
SELF_MOD = "Non puoi renderti un moderatore."
|
||||
KICK_CONFIRM = "Sei sicuro di voler espellere '@'?\nScrivi '\\#a0ffa0\\/confirm\\#fff982\\' per confermare."
|
||||
BAN_CONFIRM = "Sei sicuro di voler bandire '@'?\nScrivi'\\#a0ffa0\\/confirm\\#fff982\\' per confermare."
|
||||
PERM_BAN_CONFIRM = "Sei sicuro di voler bandire permanentemenrte '@'?\nScrivi '\\#a0ffa0\\/confirm\\#fff982\\' per confermare."
|
||||
MOD_CONFIRM = "Sei sicuro di voler rendere '@' un moderatore?\nScrivi '\\#a0ffa0\\/confirm\\#fff982\\' per confermare."
|
||||
PLAYERS_DESC = "/players - Lista dei giocatori e dei loro ID"
|
||||
KICK_DESC = "/kick [NAME|ID] - Espelli questo giocatore dalla partita"
|
||||
BAN_DESC = "/ban [NAME|ID] - Bandisci questo giocatore dalla partita"
|
||||
PERM_BAN_DESC = "/permban [NAME|ID] - Bandisci questo giocatore da tutte le tue partite"
|
||||
MOD_DESC = "/moderator [NAME|ID] - Dai al gicatore il permesso di eseguire comandi come /kick, /ban, /permban in ogni partita che crei"
|
||||
UNRECOGNIZED = "Comando non riconosciuto."
|
||||
MOD_GRANTED = "\\#fff982\\Ora sei un moderatore."
|
||||
|
||||
[MENU]
|
||||
BACK = "Indietro"
|
||||
CANCEL = "Annulla"
|
||||
NO = "No"
|
||||
YES = "Si"
|
||||
|
||||
[CAMERA]
|
||||
CAMERA = "TELECAMERA"
|
||||
FREE_CAMERA = "Telecamera libera"
|
||||
ANALOG_CAMERA = "Telecamera analogica"
|
||||
MOUSE_LOOK = "Telecamera con mouse"
|
||||
INVERT_X = "Inverti X"
|
||||
INVERT_Y = "Inverti Y"
|
||||
X_SENSITIVITY = "Inverti asse X"
|
||||
Y_SENSITIVITY = "Inverti asse Y"
|
||||
AGGRESSION = "Aggressività"
|
||||
PAN_LEVEL = "Livello di panoramica"
|
||||
DECELERATION = "Decelerazione"
|
||||
|
||||
[CHEATS]
|
||||
CHEATS = "TRUCCHI"
|
||||
MOON_JUMP = "Moon Jump"
|
||||
GOD_MODE = "God Mode"
|
||||
INFINITE_LIVES = "Vite infinite"
|
||||
SUPER_SPEED = "Super Velocità"
|
||||
RESPONSIVE_CONTROLS = "Controlli reattivi"
|
||||
RAPID_FIRE = "Fuoco Rapido (A)"
|
||||
BLJ_ANYWHERE = "BLJ Ovunque"
|
||||
ALWAYS_TRIPLE_JUMP = "Sempre Salto triplo"
|
||||
|
||||
[CONTROLS]
|
||||
CONTROLS = "CONTROLLI"
|
||||
N64_BINDS = "Comandi N64"
|
||||
EXTRA_BINDS = "Comandi Extra"
|
||||
BACKGROUND_GAMEPAD = "Azione in Background"
|
||||
GAMEPAD = "Controller"
|
||||
DEADZONE = "Zona Morta"
|
||||
RUMBLE_STRENGTH = "Intesità Vibrazione"
|
||||
CHAT = "Chat"
|
||||
PLAYERS = "Giocatori"
|
||||
D_UP = "D Su"
|
||||
D_DOWN = "D Giù"
|
||||
D_LEFT = "D Sinistra"
|
||||
D_RIGHT = "D Destra"
|
||||
X = "X"
|
||||
Y = "Y"
|
||||
|
||||
UP = "Su"
|
||||
DOWN = "Giù"
|
||||
LEFT = "Sinistra"
|
||||
RIGHT = "Destra"
|
||||
A = "A"
|
||||
B = "B"
|
||||
START = "Start"
|
||||
L = "L"
|
||||
R = "R"
|
||||
Z = "Z"
|
||||
C_UP = "C Su"
|
||||
C_DOWN = "C Giù"
|
||||
C_LEFT = "C Sinistra"
|
||||
C_RIGHT = "C Destra"
|
||||
|
||||
[DISPLAY]
|
||||
DISPLAY = "GRAFICA"
|
||||
FULLSCREEN = "Schermo intero"
|
||||
PRELOAD_TEXTURES = "Precarica Textures"
|
||||
VSYNC = "VSync"
|
||||
UNCAPPED_FRAMERATE = "Fotogrammi Illimitati"
|
||||
FRAME_LIMIT = "Limite Fotogrammi"
|
||||
FAST = "Veloce"
|
||||
ACCURATE = "Accurata"
|
||||
INTERPOLATION = "Interpolazione"
|
||||
NEAREST = "Vicino"
|
||||
LINEAR = "Lineare"
|
||||
TRIPOINT = "Tripunto"
|
||||
FILTERING = "Filtraggio"
|
||||
D0P5X = "0.5x"
|
||||
D1X = "1x"
|
||||
D1P5X = "1.5x"
|
||||
D3X = "3x"
|
||||
D10X = "10x"
|
||||
D100X = "100x"
|
||||
DRAW_DISTANCE = "Distanza di simulazione"
|
||||
DYNOS_PACKS = "Pacchetti DynOS"
|
||||
|
||||
[DYNOS]
|
||||
DYNOS = "DYNOS"
|
||||
|
||||
[HOST_MESSAGE]
|
||||
INFO_TITLE = "INFO"
|
||||
WARN_DISCORD = "Invita gli amici facendo tasto destro sul loro nome in Discord e cliccando\n'\\#d0d0ff\\Invito a giocare\\#c8c8c8\\'.\n\npuoi invitare anche i canali dei server cliccando il pulsante \\#d0d0ff\\più\\#c8c8c8\\ vicino al posto dove scrivi.\n\nLo Stato delle Attività \\#ffa0a0\\deve essere\\#c8c8c8\\ attivo nelle\nimpostazioni utente di Discord.\n\nApparire offline \\#ffa0a0\\ti impedirà\\#c8c8c8\\ di inviare inviti."
|
||||
WARN_DISCORD2 = "\\#ffa0a0\\Errore:\\#c8c8c8\\ Impossibile individuare Discord.\n\n\\#a0a0a0\\prova a chiudre il gioco,\nriavviare Discord,\ne aprire di nuovo il gioco."
|
||||
WARN_SOCKET = "La connessione diretta \\#ffa0a0\\richiede\\#c8c8c8\\ una configurazione port forwarding nel tuo router.\n\nTrasmetti una connessione '\\#d0d0ff\\%d\\#c8c8c8\\' per l'UDP."
|
||||
HOST = "Crea"
|
||||
|
||||
[HOST_MODS]
|
||||
ROMHACKS = "ROMHACKS"
|
||||
MODS = "MODS"
|
||||
|
||||
[HOST_SAVE]
|
||||
SAVE_TITLE = "SALVATAGGIO"
|
||||
ERASE_TITLE = "CANCELLA"
|
||||
CONFIRM = "Sei sicuro di voler cancellare questo slot di salvataggio?"
|
||||
ERASE = "cancella"
|
||||
|
||||
[HOST_SETTINGS]
|
||||
SETTINGS = "OPZIONI"
|
||||
NONSOLID = "Non-solida"
|
||||
SOLID = "Solida"
|
||||
FRIENDLY_FIRE = "Fuoco Amico"
|
||||
PLAYER_INTERACTION = "Interazione tra Giocatori"
|
||||
WEAK = "Debole"
|
||||
NORMAL = "Normale"
|
||||
TOO_MUCH = "Eccessiva"
|
||||
KNOCKBACK_STRENGTH = "Forza di Contraccolpo"
|
||||
LEAVE_LEVEL = "Lascia il livello"
|
||||
STAY_IN_LEVEL = "Rimani nel livello"
|
||||
NONSTOP = "Non-stop"
|
||||
ON_STAR_COLLECTION = "A stella collezzionata"
|
||||
SKIP_INTRO_CUTSCENE = "Salta la intro iniziale"
|
||||
SHARE_LIVES = "Condividi le vite"
|
||||
ENABLE_CHEATS = "Abilita i trucchi"
|
||||
BUBBLE_ON_DEATH = "Bolla alla morte"
|
||||
AMOUNT_OF_PLAYERS = "Numero di giocatori"
|
||||
|
||||
[HOST]
|
||||
SERVER_TITLE = "SERVER"
|
||||
HOST_TITLE = "OSPITA"
|
||||
DISCORD = "Discord"
|
||||
DIRECT_CONNECTION = "Connessione diretta"
|
||||
NETWORK_SYSTEM = "Sistema di connessione"
|
||||
PORT = "Porta"
|
||||
SAVE_SLOT = "Slot di Salvataggio"
|
||||
SETTINGS = "Opzioni"
|
||||
MODS = "Mods"
|
||||
ROMHACKS = "Rom-Hacks"
|
||||
APPLY = "Applica"
|
||||
HOST = "Crea"
|
||||
|
||||
[JOIN_MESSAGE]
|
||||
JOINING = "CONNESSIONE"
|
||||
|
||||
[JOIN]
|
||||
JOIN_TITLE = "UNISCITI"
|
||||
JOIN_DISCORD = "Per entrare in una partita da \\#d0d0ff\\Discord\\#c8c8c8\\:\n\nMantieni il gioco aperto e clicca sul pulsante Unisciti.\n\nSe l'invito dice che la partita è finita,/nclicca sul nome della persona che l'ha mandato per ripristinarla."
|
||||
JOIN_SOCKET = "Immetti un \\#d0d0ff\\IP e una Porta\\#c8c8c8\\ per la connessione diretta:"
|
||||
JOIN = "Unisciti"
|
||||
|
||||
[MAIN]
|
||||
QUIT_TITLE = "ABBANDONA"
|
||||
QUIT_CONFIRM = "Sei sicuro do voler abbandonare?"
|
||||
HOST = "Crea"
|
||||
JOIN = "Unisciti"
|
||||
OPTIONS = "Opzioni"
|
||||
QUIT = "Abbandona"
|
||||
|
||||
[MENU_OPTIONS]
|
||||
MAIN_MENU = "MENÙ PRINCIPALE"
|
||||
LEVEL = "Livello"
|
||||
USE_STAGE_MUSIC = "Usa la musica del livello"
|
||||
RANDOM_STAGE = "Livello casuale"
|
||||
PLAY_VANILLA_DEMOS = "Riproduci le demo di gioco"
|
||||
|
||||
[MISC]
|
||||
DEBUG_TITLE = "DEBUG"
|
||||
FIXED_COLLISIONS = "Collisioni Aggiustate"
|
||||
LUA_PROFILER = "Profiler Lua"
|
||||
DEBUG_PRINT = "Stampa di debug"
|
||||
DEBUG_INFO = "Info di debug"
|
||||
DEBUG_ERRORS = "Errori di debug"
|
||||
MISC_TITLE = "VARIE"
|
||||
PAUSE_IN_SINGLEPLAYER = "Metti in pausa in giocatore singolo"
|
||||
DISABLE_POPUPS = "Disabilita Popups"
|
||||
MENU_OPTIONS = "Opzioni Menù"
|
||||
DEBUG = "Debug"
|
||||
LANGUAGE = "Lingua"
|
||||
|
||||
[MODLIST]
|
||||
MODS = "MODS"
|
||||
|
||||
[OPTIONS]
|
||||
OPTIONS = "OPZIONI"
|
||||
PLAYER = "Giocatore"
|
||||
CAMERA = "Telecamera"
|
||||
CONTROLS = "Comandi"
|
||||
DISPLAY = "Grafica"
|
||||
SOUND = "Suono"
|
||||
MISC = "Varie"
|
||||
|
||||
[PAUSE]
|
||||
QUIT_TITLE = "ABBANDONA"
|
||||
QUIT_HOST = "Sei sicuro di voler interrompere la connessione?"
|
||||
QUIT_CLIENT = "Sei sicuro di volerti disconnettere?"
|
||||
PAUSE_TITLE = "PAUSA"
|
||||
PLAYER = "Giocatore"
|
||||
DYNOS_PACKS = "Pacchetti DynOS"
|
||||
OPTIONS = "Opzioni"
|
||||
CHEATS = "Trucchi"
|
||||
SERVER_SETTINGS = "Impostazioni Server"
|
||||
RESUME = "Riprendi"
|
||||
STOP_HOSTING = "Interrompi la connessione"
|
||||
DISCONNECT = "Disconnettiti"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "GICATORE"
|
||||
OVERALLS = "Tuta"
|
||||
SHIRT = "Maglietta"
|
||||
GLOVES = "Guanti"
|
||||
SHOES = "Scarpe"
|
||||
HAIR = "Capelli"
|
||||
SKIN = "Pelle"
|
||||
CAP = "Cappello"
|
||||
PALETTE = "PALETTE"
|
||||
PART = "Parte"
|
||||
HEX_CODE = "codice Hex"
|
||||
RED = "Rosso"
|
||||
GREEN = "Verde"
|
||||
BLUE = "Blu"
|
||||
PLAYER = "Giocatore"
|
||||
NAME = "Nome"
|
||||
MODEL = "Modello"
|
||||
PALETTE_PRESET = "Opzioni Palette"
|
||||
EDIT_PALETTE = "Modifica Palette"
|
||||
|
||||
[PALETTE]
|
||||
MARIO = "Mario"
|
||||
LUIGI = "Luigi"
|
||||
WALUIGI = "Waluigi"
|
||||
WARIO = "Wario"
|
||||
CHUCKYA = "Chuckya"
|
||||
GOOMBA = "Goomba"
|
||||
CLOVER = "Trifoglio"
|
||||
COBALT = "Cobalto"
|
||||
FURY = "Furia"
|
||||
HOT_PINK = "Rosa Caldo"
|
||||
NICE_PINK = "Rosa Fresco"
|
||||
SEAFOAM = "Schiuma Marina"
|
||||
LILAC = "Lilla"
|
||||
COPPER = "Rame"
|
||||
AZURE = "Azurro"
|
||||
BURGUNDY = "Borgogna"
|
||||
MINT = "Menta"
|
||||
EGGPLANT = "Melanzana"
|
||||
ORANGE = "Arancia"
|
||||
ARCTIC = "Arctico"
|
||||
FIRE_MARIO = "Mario Fuoco"
|
||||
FIRE_LUIGI = "Luigi Fuoco"
|
||||
FIRE_WALUIGI = "Waluigi Fuoco"
|
||||
FIRE_WARIO = "Wario Fuoco"
|
||||
BUSY_BEE = "Ape Operaia"
|
||||
FORTRESS = "Fortezza"
|
||||
BATTLEMENTS = "Muraglia"
|
||||
BLUEBERRY_PIE = "Torta ai Mirtilli"
|
||||
RASPBERRY = "Mora"
|
||||
BUBBLEGUM = "Gomma da Masticare"
|
||||
ICE_MARIO = "Mario Ghiaccio"
|
||||
ICE_LUIGI = "Luigi Ghiaccio"
|
||||
CUSTOM = "Personalizzato"
|
||||
|
||||
[PLAYER_LIST]
|
||||
PLAYERS = "GIOCATORI"
|
||||
NAME = "nome"
|
||||
LOCATION = "posizione"
|
||||
ACT = "atto"
|
||||
|
||||
[SOUND]
|
||||
SOUND = "SUONO"
|
||||
MASTER_VOLUME = "Principale"
|
||||
MUSIC_VOLUME = "Musica"
|
||||
SFX_VOLUME = "Effetti sonori"
|
||||
ENV_VOLUME = "Ambiente"
|
||||
|
||||
[LANGUAGE]
|
||||
LANGUAGE = "LINGUA"
|
|
@ -176,6 +176,7 @@ AMOUNT_OF_PLAYERS = "Quantidade de jogadores"
|
|||
SERVER_TITLE = "SERVIDOR"
|
||||
HOST_TITLE = "HOSTEAR"
|
||||
DISCORD = "Discord"
|
||||
COOPNET = "CoopNet"
|
||||
DIRECT_CONNECTION = "Conexão Direta"
|
||||
NETWORK_SYSTEM = "Sistema de Rede"
|
||||
PORT = "Porta"
|
||||
|
|
|
@ -176,6 +176,7 @@ AMOUNT_OF_PLAYERS = "Número de jugadores"
|
|||
SERVER_TITLE = "PARTIDA"
|
||||
HOST_TITLE = "CREAR"
|
||||
DISCORD = "Discord"
|
||||
COOPNET = "CoopNet"
|
||||
DIRECT_CONNECTION = "Conexión Directa"
|
||||
NETWORK_SYSTEM = "Modo de conexión"
|
||||
PORT = "Puerto"
|
||||
|
|
66
lib/coopnet/include/libcoopnet.h
Normal file
66
lib/coopnet/include/libcoopnet.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#ifndef LIBCOOPNET_H
|
||||
#define LIBCOOPNET_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include <cstdint>
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
COOPNET_OK,
|
||||
COOPNET_FAILED,
|
||||
COOPNET_DISCONNECTED,
|
||||
} CoopNetRc;
|
||||
|
||||
enum MPacketErrorNumber {
|
||||
MERR_NONE,
|
||||
MERR_LOBBY_NOT_FOUND,
|
||||
MERR_LOBBY_JOIN_FULL,
|
||||
MERR_LOBBY_JOIN_FAILED,
|
||||
MERR_LOBBY_PASSWORD_INCORRECT,
|
||||
MERR_COOPNET_VERSION,
|
||||
MERR_PEER_FAILED,
|
||||
MERR_MAX,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void (*OnConnected)(uint64_t aUserId);
|
||||
void (*OnDisconnected)(bool aIntentional);
|
||||
void (*OnLobbyCreated)(uint64_t aLobbyId, const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, uint16_t aMaxConnections);
|
||||
void (*OnLobbyJoined)(uint64_t aLobbyId, uint64_t aUserId, uint64_t aOwnerId, uint64_t aDestId);
|
||||
void (*OnLobbyLeft)(uint64_t aLobbyId, uint64_t aUserId);
|
||||
void (*OnLobbyListGot)(uint64_t aLobbyId, uint64_t aOwnerId, uint16_t aConnections, uint16_t aMaxConnections, const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, const char* aDescription);
|
||||
void (*OnLobbyListFinish)(void);
|
||||
void (*OnReceive)(uint64_t aFromUserId, const uint8_t* aData, uint64_t aSize);
|
||||
void (*OnError)(enum MPacketErrorNumber aErrorNumber, uint64_t tag);
|
||||
void (*OnPeerConnected)(uint64_t aPeerId);
|
||||
void (*OnPeerDisconnected)(uint64_t aPeerId);
|
||||
} CoopNetCallbacks;
|
||||
|
||||
typedef struct {
|
||||
bool SkipWinsockInit;
|
||||
} CoopNetSettings;
|
||||
|
||||
extern CoopNetCallbacks gCoopNetCallbacks;
|
||||
extern CoopNetSettings gCoopNetSettings;
|
||||
|
||||
bool coopnet_is_connected(void);
|
||||
CoopNetRc coopnet_begin(const char* aHost, uint32_t aPort);
|
||||
CoopNetRc coopnet_shutdown(void);
|
||||
CoopNetRc coopnet_update(void);
|
||||
CoopNetRc coopnet_lobby_create(const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, uint16_t aMaxConnections, const char* aPassword, const char* aDescription);
|
||||
CoopNetRc coopnet_lobby_update(uint64_t aLobbyId, const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, const char* aDescription);
|
||||
CoopNetRc coopnet_lobby_join(uint64_t aLobbyId, const char* aPassword);
|
||||
CoopNetRc coopnet_lobby_leave(uint64_t aLobbyId);
|
||||
CoopNetRc coopnet_lobby_list_get(const char* aGame, const char* aPassword);
|
||||
CoopNetRc coopnet_send(const uint8_t* aData, uint64_t aDataLength);
|
||||
CoopNetRc coopnet_send_to(uint64_t aPeerId, const uint8_t* aData, uint64_t aDataLength);
|
||||
CoopNetRc coopnet_unpeer(uint64_t aPeerId);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
BIN
lib/coopnet/linux/libcoopnet.a
Normal file
BIN
lib/coopnet/linux/libcoopnet.a
Normal file
Binary file not shown.
BIN
lib/coopnet/linux/libjuice.a
Normal file
BIN
lib/coopnet/linux/libjuice.a
Normal file
Binary file not shown.
BIN
lib/coopnet/win64/libcoopnet.a
Normal file
BIN
lib/coopnet/win64/libcoopnet.a
Normal file
Binary file not shown.
BIN
lib/coopnet/win64/libjuice.a
Normal file
BIN
lib/coopnet/win64/libjuice.a
Normal file
Binary file not shown.
|
@ -28,6 +28,19 @@ for i = 0, (MAX_PLAYERS - 1) do
|
|||
s.rank = 0
|
||||
end
|
||||
|
||||
local sKnockbackActions = {
|
||||
ACT_SOFT_FORWARD_GROUND_KB, ACT_FORWARD_GROUND_KB, ACT_HARD_FORWARD_GROUND_KB,
|
||||
ACT_FORWARD_AIR_KB, ACT_FORWARD_AIR_KB, ACT_HARD_FORWARD_AIR_KB,
|
||||
ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB,
|
||||
ACT_SOFT_BACKWARD_GROUND_KB, ACT_BACKWARD_GROUND_KB, ACT_HARD_BACKWARD_GROUND_KB,
|
||||
ACT_BACKWARD_AIR_KB, ACT_BACKWARD_AIR_KB, ACT_HARD_BACKWARD_AIR_KB,
|
||||
ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB,
|
||||
|
||||
ACT_LEDGE_GRAB, ACT_LEDGE_CLIMB_SLOW_1, ACT_LEDGE_CLIMB_SLOW_2, ACT_LEDGE_CLIMB_DOWN, ACT_LEDGE_CLIMB_FAST,
|
||||
ACT_GROUND_BONK, ACT_SOFT_BONK,
|
||||
|
||||
ACT_STOP_CROUCHING, ACT_STOMACH_SLIDE_STOP,
|
||||
}
|
||||
------------
|
||||
-- hammer --
|
||||
------------
|
||||
|
@ -361,6 +374,27 @@ function mario_update(m)
|
|||
local s = gPlayerSyncTable[m.playerIndex]
|
||||
local np = gNetworkPlayers[m.playerIndex]
|
||||
|
||||
-- increase knockback animations
|
||||
local animInfo = nil
|
||||
if m.marioObj ~= nil then
|
||||
animInfo = m.marioObj.header.gfx.animInfo
|
||||
end
|
||||
for i, value in ipairs(sKnockbackActions) do
|
||||
if m.action == value then
|
||||
local frame = animInfo.animFrame
|
||||
local loopEnd = frame
|
||||
if animInfo.curAnim ~= nil then
|
||||
loopEnd = animInfo.curAnim.loopEnd
|
||||
end
|
||||
|
||||
if frame < loopEnd - 2 then
|
||||
frame = frame + 1
|
||||
end
|
||||
|
||||
animInfo.animFrame = frame
|
||||
end
|
||||
end
|
||||
|
||||
-- clear invincibilities
|
||||
m.invincTimer = 0
|
||||
if m.knockbackTimer > 5 then
|
||||
|
|
|
@ -556,7 +556,7 @@ void bhv_chain_chomp_gate_init(void) {
|
|||
* Update function for chain chomp gate
|
||||
*/
|
||||
void bhv_chain_chomp_gate_update(void) {
|
||||
if (o->parentObj->oChainChompHitGate) {
|
||||
if (o->parentObj && o->parentObj->oChainChompHitGate) {
|
||||
spawn_mist_particles_with_sound(SOUND_GENERAL_WALL_EXPLOSION);
|
||||
set_camera_shake_from_point(SHAKE_POS_SMALL, o->oPosX, o->oPosY, o->oPosZ);
|
||||
spawn_mist_particles_variable(0, 0x7F, 200.0f);
|
||||
|
|
|
@ -3246,7 +3246,10 @@ void print_hud_course_complete_coins(s16 x, s16 y) {
|
|||
void play_star_fanfare_and_flash_hud(s32 arg, u8 starNum) {
|
||||
if (gHudDisplay.coins == gCourseCompleteCoins && (gCurrCourseStarFlags & starNum) == 0 && gHudFlash == 0) {
|
||||
gCurrCourseStarFlags |= starNum; // SM74 was spamming fanfare without this line
|
||||
play_star_fanfare();
|
||||
if (gFanFareDebounce <= 0) {
|
||||
gFanFareDebounce = 30 * 5;
|
||||
play_star_fanfare();
|
||||
}
|
||||
gHudFlash = arg;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
struct SavedWarpValues gReceiveWarp = { 0 };
|
||||
extern s8 sReceivedLoadedActNum;
|
||||
u8 gRejectInstantWarp = 0;
|
||||
u16 gFanFareDebounce = 0;
|
||||
|
||||
s16 gChangeLevel = -1;
|
||||
s16 gChangeLevelTransition = -1;
|
||||
|
@ -1612,6 +1613,8 @@ s32 update_level(void) {
|
|||
sFirstCastleGroundsMenu = false;
|
||||
}
|
||||
|
||||
if (gFanFareDebounce > 0) { gFanFareDebounce--; }
|
||||
|
||||
s32 changeLevel = 0;
|
||||
|
||||
if (gChangeLevel != -1) {
|
||||
|
|
|
@ -103,6 +103,7 @@ struct SavedWarpValues {
|
|||
extern struct WarpDest sWarpDest;
|
||||
extern s8 sWarpCheckpointActive;
|
||||
extern u8 gRejectInstantWarp;
|
||||
extern u16 gFanFareDebounce;
|
||||
|
||||
extern s16 D_80339EE0;
|
||||
extern s16 sDelayedWarpOp;
|
||||
|
|
|
@ -85,9 +85,6 @@ void parse_cli_opts(int argc, char* argv[]) {
|
|||
else if (strcmp(argv[i], "--savepath") == 0 && (i + 1) < argc)
|
||||
arg_string("--savepath", argv[++i], gCLIOpts.SavePath, SYS_MAX_PATH);
|
||||
|
||||
else if (strcmp(argv[i], "--discord") == 0 && (i + 1) < argc)
|
||||
arg_uint("--discord", argv[++i], &gCLIOpts.Discord);
|
||||
|
||||
// Print help
|
||||
else if (strcmp(argv[i], "--help") == 0) {
|
||||
print_help();
|
||||
|
|
|
@ -22,7 +22,6 @@ struct PCCLIOptions {
|
|||
char ConfigFile[SYS_MAX_PATH];
|
||||
char SavePath[SYS_MAX_PATH];
|
||||
char GameDir[SYS_MAX_PATH];
|
||||
unsigned int Discord;
|
||||
};
|
||||
|
||||
extern struct PCCLIOptions gCLIOpts;
|
||||
|
|
|
@ -120,9 +120,6 @@ bool configEnableCheats = 0;
|
|||
bool configBubbleDeath = true;
|
||||
unsigned int configAmountofPlayers = 16;
|
||||
bool configHUD = true;
|
||||
#ifdef DISCORDRPC
|
||||
bool configDiscordRPC = true;
|
||||
#endif
|
||||
// coop-specific
|
||||
char configJoinIp[MAX_CONFIG_STRING] = "";
|
||||
unsigned int configJoinPort = DEFAULT_PORT;
|
||||
|
@ -157,6 +154,9 @@ bool configDebugInfo = 0;
|
|||
bool configDebugError = 0;
|
||||
char configLanguage[MAX_CONFIG_STRING] = "";
|
||||
bool configForce4By3 = false;
|
||||
char configCoopNetIp[MAX_CONFIG_STRING] = DEFAULT_COOPNET_IP;
|
||||
unsigned int configCoopNetPort = DEFAULT_COOPNET_PORT;
|
||||
char configPassword[MAX_PLAYER_STRING] = "";
|
||||
|
||||
static const struct ConfigOption options[] = {
|
||||
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen},
|
||||
|
@ -211,9 +211,6 @@ static const struct ConfigOption options[] = {
|
|||
#endif
|
||||
{.name = "skip_intro", .type = CONFIG_TYPE_BOOL, .boolValue = &configSkipIntro},
|
||||
{.name = "enable_cheats", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCheats},
|
||||
#ifdef DISCORDRPC
|
||||
{.name = "discordrpc_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configDiscordRPC},
|
||||
#endif
|
||||
// debug
|
||||
{.name = "debug_offset", .type = CONFIG_TYPE_U64 , .u64Value = &gPcDebug.bhvOffset},
|
||||
{.name = "debug_tags", .type = CONFIG_TYPE_U64 , .u64Value = gPcDebug.tags},
|
||||
|
@ -266,6 +263,9 @@ static const struct ConfigOption options[] = {
|
|||
{.name = "debug_error", .type = CONFIG_TYPE_BOOL , .boolValue = &configDebugError},
|
||||
{.name = "language", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configLanguage, .maxStringLength = MAX_CONFIG_STRING},
|
||||
{.name = "force_4by3", .type = CONFIG_TYPE_BOOL, .boolValue = &configForce4By3},
|
||||
{.name = "coopnet_ip", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configCoopNetIp, .maxStringLength = MAX_CONFIG_STRING},
|
||||
{.name = "coopnet_port", .type = CONFIG_TYPE_UINT , .uintValue = &configCoopNetPort},
|
||||
{.name = "coopnet_password", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configPassword, .maxStringLength = MAX_CONFIG_STRING},
|
||||
};
|
||||
|
||||
// FunctionConfigOption functions
|
||||
|
@ -554,8 +554,8 @@ NEXT_OPTION:
|
|||
if (configFrameLimit < 30) { configFrameLimit = 30; }
|
||||
if (configFrameLimit > 3000) { configFrameLimit = 3000; }
|
||||
|
||||
#ifndef DISCORD_SDK
|
||||
configNetworkSystem = 1;
|
||||
#ifndef COOPNET
|
||||
configNetworkSystem = NS_SOCKET;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#define MAX_DESCRIPTION_STRING 20
|
||||
|
||||
#define DEFAULT_PORT 7777
|
||||
#define DEFAULT_COOPNET_IP "net.coop64.us"
|
||||
#define DEFAULT_COOPNET_PORT 34197
|
||||
|
||||
typedef struct {
|
||||
unsigned int x, y, w, h;
|
||||
|
@ -78,9 +80,6 @@ extern bool configShareLives;
|
|||
extern bool configEnableCheats;
|
||||
extern bool configBubbleDeath;
|
||||
extern unsigned int configAmountofPlayers;
|
||||
#ifdef DISCORDRPC
|
||||
extern bool configDiscordRPC;
|
||||
#endif
|
||||
extern char configJoinIp[];
|
||||
extern unsigned int configJoinPort;
|
||||
extern unsigned int configHostPort;
|
||||
|
@ -112,6 +111,9 @@ extern bool configDebugInfo;
|
|||
extern bool configDebugError;
|
||||
extern char configLanguage[];
|
||||
extern bool configForce4By3;
|
||||
extern char configCoopNetIp[];
|
||||
extern unsigned int configCoopNetPort;
|
||||
extern char configPassword[];
|
||||
|
||||
void configfile_load(void);
|
||||
void configfile_save(const char *filename);
|
||||
|
|
168
src/pc/discord/discord.c
Normal file
168
src/pc/discord/discord.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
#include "discord.h"
|
||||
#include "pc/djui/djui.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#include <winuser.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
|
||||
#define MAX_LAUNCH_CMD (MAX_PATH + 12)
|
||||
|
||||
static int64_t applicationId = 752700005210390568;
|
||||
struct DiscordApplication app = { 0 };
|
||||
static bool sFatalShown = false;
|
||||
static bool sDiscordInitialized = false;
|
||||
static bool sDiscordFailed = false;
|
||||
|
||||
static void discord_sdk_log_callback(UNUSED void* hook_data, enum EDiscordLogLevel level, const char* message) {
|
||||
LOG_INFO("callback (%d): %s", level, message);
|
||||
}
|
||||
|
||||
void discord_fatal_message(int rc) { // Discord usually does this because of loss of connection to Discord
|
||||
LOG_ERROR("Discord fatal: %d", rc);
|
||||
/*char errorMessage[132] = { 0 };
|
||||
snprintf(errorMessage, 132, "%s\nRC: %d", DLANG(NOTIF, DISCORD_ERROR), rc);
|
||||
djui_popup_create(errorMessage, 6);*/
|
||||
}
|
||||
|
||||
void discord_fatal(int rc) {
|
||||
if (!sFatalShown) {
|
||||
discord_fatal_message(rc);
|
||||
sFatalShown = true;
|
||||
}
|
||||
|
||||
if (rc != DiscordResult_Ok) {
|
||||
LOG_ERROR("Discord threw an error. RC: %d", 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);
|
||||
if (result != DiscordResult_Ok) { return; }
|
||||
LOG_INFO("OAuth2 token: %s", token->access_token);
|
||||
}
|
||||
|
||||
static void register_launch_command(void) {
|
||||
char cmd[MAX_LAUNCH_CMD] = { 0 };
|
||||
int rc;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HMODULE hModule = GetModuleHandle(NULL);
|
||||
if (hModule == NULL) {
|
||||
LOG_ERROR("unable to retrieve absolute path!");
|
||||
return;
|
||||
}
|
||||
GetModuleFileName(hModule, cmd, sizeof(cmd));
|
||||
#else
|
||||
char pidpath[MAX_LAUNCH_CMD] = { 0 };
|
||||
char fullpath[MAX_LAUNCH_CMD] = { 0 };
|
||||
snprintf(pidpath, MAX_LAUNCH_CMD - 1, "/proc/%d/exe", getpid());
|
||||
rc = readlink(pidpath, fullpath, MAX_LAUNCH_CMD - 1);
|
||||
if (rc <= 0) {
|
||||
LOG_ERROR("unable to retrieve absolute path! rc = %d", rc);
|
||||
return;
|
||||
}
|
||||
snprintf(cmd, MAX_LAUNCH_CMD, "%s", fullpath);
|
||||
#endif
|
||||
rc = app.activities->register_command(app.activities, cmd);
|
||||
if (rc != DiscordResult_Ok) {
|
||||
LOG_ERROR("register command failed %d", rc);
|
||||
return;
|
||||
}
|
||||
LOG_INFO("cmd: %s", cmd);
|
||||
}
|
||||
|
||||
static void on_current_user_update(UNUSED void* data) {
|
||||
LOG_INFO("> on_current_user_update");
|
||||
struct DiscordUser user = { 0 };
|
||||
app.users->get_current_user(app.users, &user);
|
||||
|
||||
// remember user id
|
||||
app.userId = user.id;
|
||||
|
||||
// copy over discord username if we haven't set one yet
|
||||
if (configPlayerName[0] == '\0' && strlen(user.username) > 0) {
|
||||
char* cname = configPlayerName;
|
||||
char* dname = user.username;
|
||||
for (int i = 0; i < MAX_PLAYER_STRING - 1; i++) {
|
||||
if (*dname >= '!' && *dname <= '~') {
|
||||
*cname = *dname;
|
||||
cname++;
|
||||
}
|
||||
dname++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IDiscordUserEvents* discord_user_initialize(void) {
|
||||
LOG_INFO("> discord_user_intitialize");
|
||||
static struct IDiscordUserEvents events = { 0 };
|
||||
events.on_current_user_update = on_current_user_update;
|
||||
return &events;
|
||||
}
|
||||
|
||||
static void discord_initialize(void) {
|
||||
if (sDiscordInitialized) { return; }
|
||||
sDiscordInitialized = true;
|
||||
|
||||
if (app.core != NULL) {
|
||||
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
|
||||
}
|
||||
|
||||
// set up discord params
|
||||
struct DiscordCreateParams params = { 0 };
|
||||
DiscordCreateParamsSetDefault(¶ms);
|
||||
params.client_id = applicationId;
|
||||
params.flags = DiscordCreateFlags_NoRequireDiscord;
|
||||
params.event_data = &app;
|
||||
params.user_events = discord_user_initialize();
|
||||
params.activity_events = discord_activity_initialize();
|
||||
|
||||
int rc = DiscordCreate(DISCORD_VERSION, ¶ms, &app.core);
|
||||
if (app.core != NULL) {
|
||||
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
LOG_ERROR("DiscordCreate failed: %d", rc);
|
||||
//djui_popup_create(DLANG(NOTIF, DISCORD_DETECT), 3);
|
||||
sDiscordFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// set up manager pointers
|
||||
if (app.core != NULL) {
|
||||
app.users = app.core->get_user_manager(app.core);
|
||||
app.achievements = app.core->get_achievement_manager(app.core);
|
||||
app.activities = app.core->get_activity_manager(app.core);
|
||||
app.application = app.core->get_application_manager(app.core);
|
||||
}
|
||||
|
||||
// get oath2 token
|
||||
app.application->get_oauth2_token(app.application, NULL, get_oauth2_token_callback);
|
||||
|
||||
// set activity
|
||||
discord_activity_update();
|
||||
sDiscordFailed = false;
|
||||
|
||||
// register launch params
|
||||
register_launch_command();
|
||||
|
||||
LOG_INFO("initialized");
|
||||
}
|
||||
|
||||
u64 discord_get_user_id(void) {
|
||||
return app.userId;
|
||||
}
|
||||
|
||||
void discord_update(void) {
|
||||
if (sDiscordFailed) { return; }
|
||||
if (!sDiscordInitialized) { discord_initialize(); }
|
||||
if (sDiscordFailed) { return; }
|
||||
|
||||
discord_activity_update_check();
|
||||
DISCORD_REQUIRE(app.core->run_callbacks(app.core));
|
||||
}
|
|
@ -1,22 +1,14 @@
|
|||
#ifndef DISCORD_H
|
||||
#define DISCORD_H
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#pragma pack(push, 8)
|
||||
#pragma once
|
||||
|
||||
#include "PR/ultratypes.h"
|
||||
#include "discord_game_sdk.h"
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DISCORD_ID_FORMAT "%lld"
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#define DISCORD_ID_FORMAT "%ld"
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include "../network.h"
|
||||
|
||||
void discord_fatal(int rc);
|
||||
|
||||
// disgusting but descriptive
|
||||
#define DISCORD_REQUIRE(x) { \
|
||||
|
@ -26,10 +18,6 @@ void discord_fatal(int rc);
|
|||
} \
|
||||
}
|
||||
|
||||
extern struct NetworkSystem gNetworkSystemDiscord;
|
||||
extern bool gDiscordInitialized;
|
||||
extern bool gDiscordFailed;
|
||||
|
||||
struct DiscordApplication {
|
||||
struct IDiscordCore* core;
|
||||
struct IDiscordUserManager* users;
|
||||
|
@ -41,6 +29,9 @@ struct DiscordApplication {
|
|||
DiscordUserId userId;
|
||||
};
|
||||
|
||||
extern struct DiscordApplication app;
|
||||
|
||||
#endif
|
||||
void discord_update(void);
|
||||
void discord_fatal(int rc);
|
||||
void discord_activity_update_check(void);
|
||||
void discord_activity_update(void);
|
||||
struct IDiscordActivityEvents* discord_activity_initialize(void);
|
||||
u64 discord_get_user_id(void);
|
176
src/pc/discord/discord_activity.c
Normal file
176
src/pc/discord/discord_activity.c
Normal file
|
@ -0,0 +1,176 @@
|
|||
#include "discord.h"
|
||||
#include "pc/djui/djui.h"
|
||||
#include "pc/mods/mods.h"
|
||||
#include "pc/debuglog.h"
|
||||
#include "pc/utils/misc.h"
|
||||
#include "pc/djui/djui_panel_join_message.h"
|
||||
#ifdef COOPNET
|
||||
#include "pc/network/coopnet/coopnet.h"
|
||||
#endif
|
||||
|
||||
extern struct DiscordApplication app;
|
||||
struct DiscordActivity sCurActivity = { 0 };
|
||||
static int sQueuedLobby = 0;
|
||||
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);
|
||||
DISCORD_REQUIRE(result);
|
||||
}
|
||||
|
||||
static void on_activity_join(UNUSED void* data, const char* secret) {
|
||||
LOG_INFO("> on_activity_join, secret: %s", secret);
|
||||
char *token;
|
||||
|
||||
// extract lobby type
|
||||
token = strtok((char*)secret, ":");
|
||||
if (strcmp(token, "coopnet") != 0) {
|
||||
LOG_ERROR("Tried to join unrecognized lobby type: %s", token);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef COOPNET
|
||||
// extract lobby ID
|
||||
token = strtok(NULL, ":");
|
||||
char* end;
|
||||
u64 lobbyId = strtoull(token, &end, 10);
|
||||
|
||||
// extract lobby password
|
||||
token = strtok(NULL, ":");
|
||||
if (token == NULL) { token = ""; }
|
||||
|
||||
// join
|
||||
if (gNetworkType != NT_NONE) {
|
||||
network_shutdown(true, false, false, false);
|
||||
}
|
||||
sQueuedLobbyId = lobbyId;
|
||||
snprintf(sQueuedLobbyPassword, 64, "%s", token);
|
||||
sQueuedLobby = 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void on_activity_join_request_callback(UNUSED void* data, enum EDiscordResult 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);
|
||||
}
|
||||
|
||||
static void strncat_len(char* destination, char* source, size_t destinationLength, size_t sourceLength) {
|
||||
char altered[128] = { 0 };
|
||||
snprintf(altered, (sourceLength < 127) ? sourceLength : 127, "%s", source);
|
||||
strncat(destination, altered, destinationLength);
|
||||
}
|
||||
|
||||
static void discord_populate_details(char* buffer, int bufferLength) {
|
||||
// get version
|
||||
char* version = get_version();
|
||||
int versionLength = strlen(version);
|
||||
snprintf(buffer, bufferLength, "%s", version);
|
||||
buffer += versionLength;
|
||||
bufferLength -= versionLength;
|
||||
|
||||
// get mod strings
|
||||
if (gActiveMods.entryCount <= 0) { return; }
|
||||
char* strings[gActiveMods.entryCount];
|
||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||
strings[i] = gActiveMods.entries[i]->name;
|
||||
}
|
||||
|
||||
// add seperator
|
||||
snprintf(buffer, bufferLength, "%s", " - ");
|
||||
buffer += 3;
|
||||
bufferLength -= 3;
|
||||
|
||||
// concat mod strings
|
||||
str_seperator_concat(buffer, bufferLength, strings, gActiveMods.entryCount, ", ");
|
||||
}
|
||||
|
||||
void discord_activity_update(void) {
|
||||
sCurActivity.type = DiscordActivityType_Playing;
|
||||
|
||||
if (gNetworkType != NT_NONE && gNetworkSystem) {
|
||||
gNetworkSystem->get_lobby_id(sCurActivity.party.id, 128);
|
||||
gNetworkSystem->get_lobby_secret(sCurActivity.secrets.join, 128);
|
||||
sCurActivity.party.size.current_size = network_player_connected_count();
|
||||
sCurActivity.party.size.max_size = gServerSettings.maxPlayers;
|
||||
} else {
|
||||
snprintf(sCurActivity.party.id, 128, "%s", "");
|
||||
snprintf(sCurActivity.secrets.join, 128, "%s", "");
|
||||
sCurActivity.party.size.current_size = 1;
|
||||
sCurActivity.party.size.max_size = 1;
|
||||
}
|
||||
|
||||
if (sCurActivity.party.size.current_size > 1) {
|
||||
strcpy(sCurActivity.state, "Playing!");
|
||||
} else if (gNetworkType == NT_SERVER) {
|
||||
strcpy(sCurActivity.state, "Waiting for players...");
|
||||
} else {
|
||||
strcpy(sCurActivity.state, "In-game.");
|
||||
sCurActivity.party.size.current_size = 1;
|
||||
if (sCurActivity.party.size.max_size < 1) { sCurActivity.party.size.max_size = 1; }
|
||||
}
|
||||
|
||||
char details[128] = { 0 };
|
||||
discord_populate_details(details, 128);
|
||||
|
||||
if (snprintf(sCurActivity.details, 128, "%s", details) < 0) {
|
||||
LOG_INFO("truncating details");
|
||||
}
|
||||
|
||||
if (!app.activities) {
|
||||
LOG_INFO("no activities");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!app.activities->update_activity) {
|
||||
LOG_INFO("no update_activity");
|
||||
return;
|
||||
}
|
||||
|
||||
app.activities->update_activity(app.activities, &sCurActivity, NULL, on_activity_update_callback);
|
||||
LOG_INFO("set activity");
|
||||
}
|
||||
|
||||
void discord_activity_update_check(void) {
|
||||
if (sQueuedLobby > 0) {
|
||||
if (--sQueuedLobby == 0) {
|
||||
gCoopNetDesiredLobby = sQueuedLobbyId;
|
||||
snprintf(gCoopNetPassword, 64, "%s", sQueuedLobbyPassword);
|
||||
network_reset_reconnect_and_rehost();
|
||||
network_set_system(NS_COOPNET);
|
||||
network_init(NT_CLIENT, false);
|
||||
djui_panel_join_message_create(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (gNetworkType == NT_NONE) { return; }
|
||||
bool shouldUpdate = false;
|
||||
u8 connectedCount = network_player_connected_count();
|
||||
|
||||
if (connectedCount > 0) {
|
||||
if (connectedCount != sCurActivity.party.size.current_size) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int updateTimer = 30 * 60;
|
||||
if (--updateTimer <= 0) {
|
||||
updateTimer = 30 * 60;
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
discord_activity_update();
|
||||
}
|
||||
}
|
||||
|
||||
struct IDiscordActivityEvents* discord_activity_initialize(void) {
|
||||
static struct IDiscordActivityEvents events = { 0 };
|
||||
events.on_activity_join = on_activity_join;
|
||||
events.on_activity_join_request = on_activity_join_request;
|
||||
return &events;
|
||||
}
|
|
@ -1,291 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "PR/ultratypes.h"
|
||||
#include "game/memory.h"
|
||||
#include "game/save_file.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "discordrpc.h"
|
||||
|
||||
#define DISCORDLIBFILE "libdiscord-rpc"
|
||||
|
||||
// Thanks Microsoft for being non posix compliant
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
# define DISCORDLIBEXT ".dll"
|
||||
# define dlopen(lib, flag) LoadLibrary(TEXT(lib))
|
||||
# define dlerror() ""
|
||||
# define dlsym(handle, func) (void *)GetProcAddress(handle, func)
|
||||
# define dlclose(handle) FreeLibrary(handle)
|
||||
#elif defined(__APPLE__)
|
||||
# include <dlfcn.h>
|
||||
# define DISCORDLIBEXT ".dylib"
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) // lets make the bold assumption for FreeBSD
|
||||
# include <dlfcn.h>
|
||||
# define DISCORDLIBEXT ".so"
|
||||
#else
|
||||
# error Unknown System
|
||||
#endif
|
||||
|
||||
#define DISCORDLIB DISCORDLIBFILE DISCORDLIBEXT
|
||||
#define DISCORD_APP_ID "709083908708237342"
|
||||
#define DISCORD_UPDATE_RATE 5
|
||||
|
||||
extern s16 gCurrCourseNum;
|
||||
extern s16 gCurrActNum;
|
||||
extern u8* seg2_course_name_table[];
|
||||
extern u8* seg2_act_name_table[];
|
||||
|
||||
static time_t lastUpdatedTime;
|
||||
|
||||
static DiscordRichPresence discordRichPresence;
|
||||
static bool initd = false;
|
||||
|
||||
static void* handle;
|
||||
|
||||
void (*Discord_Initialize)(const char *, DiscordEventHandlers *, int, const char *);
|
||||
void (*Discord_Shutdown)(void);
|
||||
void (*Discord_ClearPresence)(void);
|
||||
void (*Discord_UpdatePresence)(DiscordRichPresence *);
|
||||
|
||||
static s16 lastCourseNum = -1;
|
||||
static s16 lastActNum = -1;
|
||||
|
||||
#ifdef VERSION_EU
|
||||
#include "eu_translation.h"
|
||||
extern s32 gInGameLanguage;
|
||||
#endif
|
||||
|
||||
static char stage[188];
|
||||
static char act[188];
|
||||
|
||||
static char smallImageKey[5];
|
||||
static char largeImageKey[5];
|
||||
|
||||
static const char charset[0xFF+1] = {
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 7
|
||||
' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', // 15
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 23
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 31
|
||||
'w', 'x', 'y', 'z', ' ', ' ', ' ', ' ', // 39
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 49
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 55
|
||||
' ', ' ', ' ', ' ', ' ', ' ', '\'', ' ', // 63
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 71
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 79
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 87
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 95
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 103
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ',', // 111
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 119
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 127
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 135
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 143
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 151
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', // 159
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 167
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 175
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 183
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 192
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 199
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 207
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 215
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 223
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 231
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 239
|
||||
' ', ' ', '!', ' ', ' ', ' ', ' ', ' ', // 247
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' // 255
|
||||
};
|
||||
|
||||
static void convertstring(const u8 *str, char* output) {
|
||||
s32 strPos = 0;
|
||||
bool capitalizeChar = true;
|
||||
|
||||
while (str[strPos] != 0xFF) {
|
||||
if (str[strPos] < 0xFF) {
|
||||
output[strPos] = charset[str[strPos]];
|
||||
|
||||
// if the char is a letter we can capatalize it
|
||||
if (capitalizeChar && 0x0A <= str[strPos] && str[strPos] <= 0x23) {
|
||||
output[strPos] -= ('a' - 'A');
|
||||
capitalizeChar = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
output[strPos] = ' ';
|
||||
}
|
||||
|
||||
// decide if the next character should be capitalized
|
||||
switch (output[strPos]) {
|
||||
case ' ':
|
||||
if (str[strPos] != 158)
|
||||
fprintf(stdout, "Unknown Character (%i)\n", str[strPos]); // inform that an unknown char was found
|
||||
case '-':
|
||||
capitalizeChar = true;
|
||||
break;
|
||||
default:
|
||||
capitalizeChar = false;
|
||||
break;
|
||||
}
|
||||
|
||||
strPos++;
|
||||
}
|
||||
|
||||
output[strPos] = '\0';
|
||||
}
|
||||
|
||||
static void on_ready(UNUSED const DiscordUser* user) {
|
||||
discord_reset();
|
||||
}
|
||||
|
||||
static void init_discord(void) {
|
||||
DiscordEventHandlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
handlers.ready = on_ready;
|
||||
|
||||
Discord_Initialize(DISCORD_APP_ID, &handlers, false, "");
|
||||
|
||||
initd = true;
|
||||
}
|
||||
|
||||
static void set_details(void) {
|
||||
if (lastCourseNum != gCurrCourseNum) {
|
||||
// If we are in in Course 0 we are in the castle which doesn't have a string
|
||||
if (gCurrCourseNum) {
|
||||
void **courseNameTbl;
|
||||
|
||||
#ifndef VERSION_EU
|
||||
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
|
||||
#else
|
||||
switch (gInGameLanguage) {
|
||||
case LANGUAGE_ENGLISH:
|
||||
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
|
||||
break;
|
||||
case LANGUAGE_FRENCH:
|
||||
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
u8 *courseName = segmented_to_virtual(courseNameTbl[gCurrCourseNum - 1]);
|
||||
|
||||
convertstring(&courseName[3], stage);
|
||||
} else {
|
||||
strcpy(stage, "Peach's Castle");
|
||||
}
|
||||
|
||||
lastCourseNum = gCurrCourseNum;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_state(void) {
|
||||
if (lastActNum != gCurrActNum || lastCourseNum != gCurrCourseNum) {
|
||||
// when exiting a stage the act doesn't get reset
|
||||
if (gCurrActNum && gCurrCourseNum) {
|
||||
// any stage over 19 is a special stage without acts
|
||||
if (gCurrCourseNum < 19) {
|
||||
void **actNameTbl;
|
||||
#ifndef VERSION_EU
|
||||
actNameTbl = segmented_to_virtual(seg2_act_name_table);
|
||||
#else
|
||||
switch (gInGameLanguage) {
|
||||
case LANGUAGE_ENGLISH:
|
||||
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
|
||||
break;
|
||||
case LANGUAGE_FRENCH:
|
||||
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
u8 *actName = actName = segmented_to_virtual(actNameTbl[(gCurrCourseNum - 1) * 6 + gCurrActNum - 1]);
|
||||
|
||||
convertstring(actName, act);
|
||||
} else {
|
||||
act[0] = '\0';
|
||||
gCurrActNum = 0;
|
||||
}
|
||||
} else {
|
||||
act[0] = '\0';
|
||||
}
|
||||
|
||||
lastActNum = gCurrActNum;
|
||||
}
|
||||
}
|
||||
|
||||
void set_logo(void) {
|
||||
if (lastCourseNum)
|
||||
snprintf(largeImageKey, sizeof(largeImageKey), "%d", lastCourseNum);
|
||||
else
|
||||
strcpy(largeImageKey, "0");
|
||||
|
||||
/*
|
||||
if (lastActNum)
|
||||
snprintf(smallImageKey, sizeof(largeImageKey), "%d", lastActNum);
|
||||
else
|
||||
smallImageKey[0] = '\0';
|
||||
*/
|
||||
|
||||
discordRichPresence.largeImageKey = largeImageKey;
|
||||
//discordRichPresence.largeImageText = "";
|
||||
//discordRichPresence.smallImageKey = smallImageKey;
|
||||
//discordRichPresence.smallImageText = "";
|
||||
}
|
||||
|
||||
void discord_update_rich_presence(void) {
|
||||
if (!configDiscordRPC || !initd) return;
|
||||
if (time(NULL) < lastUpdatedTime + DISCORD_UPDATE_RATE) return;
|
||||
|
||||
lastUpdatedTime = time(NULL);
|
||||
|
||||
set_state();
|
||||
set_details();
|
||||
set_logo();
|
||||
Discord_UpdatePresence(&discordRichPresence);
|
||||
}
|
||||
|
||||
void discord_shutdown(void) {
|
||||
if (handle) {
|
||||
Discord_ClearPresence();
|
||||
Discord_Shutdown();
|
||||
dlclose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void discord_init(void) {
|
||||
if (configDiscordRPC) {
|
||||
handle = dlopen(DISCORDLIB, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
fprintf(stderr, "Unable to load Discord\n%s\n", dlerror());
|
||||
return;
|
||||
}
|
||||
|
||||
Discord_Initialize = dlsym(handle, "Discord_Initialize");
|
||||
Discord_Shutdown = dlsym(handle, "Discord_Shutdown");
|
||||
Discord_ClearPresence = dlsym(handle, "Discord_ClearPresence");
|
||||
Discord_UpdatePresence = dlsym(handle, "Discord_UpdatePresence");
|
||||
|
||||
init_discord();
|
||||
|
||||
discordRichPresence.details = stage;
|
||||
discordRichPresence.state = act;
|
||||
|
||||
lastUpdatedTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void discord_reset(void) {
|
||||
memset( &discordRichPresence, 0, sizeof( discordRichPresence ) );
|
||||
|
||||
set_state();
|
||||
set_details();
|
||||
set_logo();
|
||||
Discord_UpdatePresence(&discordRichPresence);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
#ifndef DISCORDRPC_H
|
||||
#define DISCORDRPC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct DiscordRichPresence {
|
||||
const char* state; /* max 128 bytes */
|
||||
const char* details; /* max 128 bytes */
|
||||
int64_t startTimestamp;
|
||||
int64_t endTimestamp;
|
||||
const char* largeImageKey; /* max 32 bytes */
|
||||
const char* largeImageText; /* max 128 bytes */
|
||||
const char* smallImageKey; /* max 32 bytes */
|
||||
const char* smallImageText; /* max 128 bytes */
|
||||
const char* partyId; /* max 128 bytes */
|
||||
int partySize;
|
||||
int partyMax;
|
||||
const char* matchSecret; /* max 128 bytes */
|
||||
const char* joinSecret; /* max 128 bytes */
|
||||
const char* spectateSecret; /* max 128 bytes */
|
||||
int8_t instance;
|
||||
} DiscordRichPresence;
|
||||
|
||||
typedef struct DiscordUser {
|
||||
const char* userId;
|
||||
const char* username;
|
||||
const char* discriminator;
|
||||
const char* avatar;
|
||||
} DiscordUser;
|
||||
|
||||
typedef struct DiscordEventHandlers {
|
||||
void (*ready)(const DiscordUser* request);
|
||||
void (*disconnected)(int errorCode, const char* message);
|
||||
void (*errored)(int errorCode, const char* message);
|
||||
void (*joinGame)(const char* joinSecret);
|
||||
void (*spectateGame)(const char* spectateSecret);
|
||||
void (*joinRequest)(const DiscordUser* request);
|
||||
} DiscordEventHandlers;
|
||||
|
||||
#define DISCORD_REPLY_NO 0
|
||||
#define DISCORD_REPLY_YES 1
|
||||
#define DISCORD_REPLY_IGNORE 2
|
||||
|
||||
void discord_update_rich_presence(void);
|
||||
void discord_shutdown(void);
|
||||
void discord_init(void);
|
||||
void discord_reset(void);
|
||||
|
||||
#endif // DISCORDRPC_H
|
|
@ -393,6 +393,19 @@ void djui_base_destroy(struct DjuiBase* base) {
|
|||
base->destroy(base);
|
||||
}
|
||||
|
||||
void djui_base_destroy_children(struct DjuiBase* base) {
|
||||
// destroy all children and our linked list
|
||||
struct DjuiBaseChild* child = base->child;
|
||||
while (child != NULL) {
|
||||
struct DjuiBaseChild* nextChild = child->next;
|
||||
child->base->parent = NULL;
|
||||
djui_base_destroy(child->base);
|
||||
free(child);
|
||||
child = nextChild;
|
||||
}
|
||||
base->child = NULL;
|
||||
}
|
||||
|
||||
void djui_base_init(struct DjuiBase* parent, struct DjuiBase* base, bool (*render)(struct DjuiBase*), void (*destroy)(struct DjuiBase*)) {
|
||||
memset(base, 0, sizeof(struct DjuiBase));
|
||||
base->parent = parent;
|
||||
|
|
|
@ -41,7 +41,7 @@ struct DjuiBase {
|
|||
struct DjuiInteractable* interactable;
|
||||
bool addChildrenToHead;
|
||||
bool abandonAfterChildRenderFail;
|
||||
s32 tag;
|
||||
s64 tag;
|
||||
bool bTag;
|
||||
void (*get_cursor_hover_location)(struct DjuiBase*, f32* x, f32* y);
|
||||
void (*on_child_render)(struct DjuiBase*, struct DjuiBase*);
|
||||
|
@ -69,4 +69,5 @@ void djui_base_compute_tree(struct DjuiBase* base);
|
|||
|
||||
bool djui_base_render(struct DjuiBase* base);
|
||||
void djui_base_destroy(struct DjuiBase* base);
|
||||
void djui_base_destroy_children(struct DjuiBase* base);
|
||||
void djui_base_init(struct DjuiBase* parent, struct DjuiBase* base, bool (*render)(struct DjuiBase*), void (*destroy)(struct DjuiBase*));
|
||||
|
|
|
@ -62,7 +62,6 @@ static f32 djui_cursor_base_distance(struct DjuiBase* base, f32 xScale, f32 ySca
|
|||
|
||||
static void djui_cursor_move_check(s8 xDir, s8 yDir, struct DjuiBase** pick, struct DjuiBase* base) {
|
||||
if (!base->visible) { return; }
|
||||
if (!base->enabled) { return; }
|
||||
|
||||
if (base->interactable != NULL) {
|
||||
f32 x1, y1, x2, y2;
|
||||
|
|
|
@ -292,13 +292,13 @@ void djui_inputbox_on_key_up(UNUSED struct DjuiBase *base, int scancode) {
|
|||
}
|
||||
}
|
||||
|
||||
static void djui_inputbox_on_focus_begin(UNUSED struct DjuiBase* base) {
|
||||
void djui_inputbox_on_focus_begin(UNUSED struct DjuiBase* base) {
|
||||
sHeldControl = 0;
|
||||
sHeldShift = 0;
|
||||
wm_api->start_text_input();
|
||||
}
|
||||
|
||||
static void djui_inputbox_on_focus_end(UNUSED struct DjuiBase* base) {
|
||||
void djui_inputbox_on_focus_end(UNUSED struct DjuiBase* base) {
|
||||
wm_api->stop_text_input();
|
||||
}
|
||||
|
||||
|
@ -373,15 +373,17 @@ static void djui_inputbox_render_char(struct DjuiInputbox* inputbox, char* c, f3
|
|||
f32 dW = font->charWidth * font->defaultFontScale;
|
||||
f32 dH = font->charHeight * font->defaultFontScale;
|
||||
|
||||
f32 charWidth = font->char_width(c);
|
||||
char* dc = inputbox->passwordChar[0] ? inputbox->passwordChar : c;
|
||||
|
||||
f32 charWidth = font->char_width(dc);
|
||||
*drawX += charWidth * font->defaultFontScale;
|
||||
|
||||
if (*c != ' ' && !djui_gfx_add_clipping_specific(&inputbox->base, dX, dY, dW, dH)) {
|
||||
if (*dc != ' ' && !djui_gfx_add_clipping_specific(&inputbox->base, dX, dY, dW, dH)) {
|
||||
if (*additionalShift > 0) {
|
||||
create_dl_translation_matrix(DJUI_MTX_NOPUSH, *additionalShift, 0, 0);
|
||||
*additionalShift = 0;
|
||||
}
|
||||
font->render_char(c);
|
||||
font->render_char(dc);
|
||||
}
|
||||
*additionalShift += charWidth;
|
||||
}
|
||||
|
@ -398,10 +400,11 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
|
|||
f32 x = 0;
|
||||
f32 width = 0;
|
||||
for (u16 i = 0; i < selection[1]; i++) {
|
||||
char* dc = inputbox->passwordChar[0] ? inputbox->passwordChar : c;
|
||||
if (i < selection[0]) {
|
||||
x += font->char_width(c);
|
||||
x += font->char_width(dc);
|
||||
} else {
|
||||
width += font->char_width(c);
|
||||
width += font->char_width(dc);
|
||||
}
|
||||
c = djui_unicode_next_char(c);
|
||||
}
|
||||
|
@ -458,7 +461,8 @@ static void djui_inputbox_keep_selection_in_view(struct DjuiInputbox* inputbox)
|
|||
char* c = inputbox->buffer;
|
||||
for (u16 i = 0; i < inputbox->selection[0]; i++) {
|
||||
if (*c == '\0') { break; }
|
||||
cursorX += font->char_width(c) * font->defaultFontScale;
|
||||
char* dc = inputbox->passwordChar[0] ? inputbox->passwordChar : c;
|
||||
cursorX += font->char_width(dc) * font->defaultFontScale;
|
||||
c = djui_unicode_next_char(c);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
struct DjuiInputbox {
|
||||
struct DjuiBase base;
|
||||
char* buffer;
|
||||
char passwordChar[2];
|
||||
u16 bufferSize;
|
||||
u16 selection[2];
|
||||
f32 viewX;
|
||||
|
@ -12,6 +13,8 @@ struct DjuiInputbox {
|
|||
void (*on_escape_press)(struct DjuiInputbox*);
|
||||
};
|
||||
|
||||
void djui_inputbox_on_focus_begin(UNUSED struct DjuiBase* base);
|
||||
void djui_inputbox_on_focus_end(UNUSED struct DjuiBase* base);
|
||||
void djui_inputbox_set_text_color(struct DjuiInputbox* inputbox, u8 r, u8 g, u8 b, u8 a);
|
||||
void djui_inputbox_set_text(struct DjuiInputbox* inputbox, char* text);
|
||||
void djui_inputbox_select_all(struct DjuiInputbox* inputbox);
|
||||
|
|
85
src/pc/djui/djui_lobby_entry.c
Normal file
85
src/pc/djui/djui_lobby_entry.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "djui.h"
|
||||
#include "djui_lobby_entry.h"
|
||||
|
||||
#define VK_ESCAPE 1
|
||||
|
||||
static void djui_lobby_entry_update_style(struct DjuiBase* base) {
|
||||
struct DjuiLobbyEntry* entry = (struct DjuiLobbyEntry*)base;
|
||||
if (!entry->base.enabled) {
|
||||
u8 borderBrightness = 75;
|
||||
u8 rectBrightness = 111;
|
||||
djui_base_set_border_color(base, borderBrightness, borderBrightness, borderBrightness, 255);
|
||||
djui_base_set_color(&entry->base, rectBrightness, rectBrightness, rectBrightness, 255);
|
||||
//djui_base_set_location(&entry->text->base, 0.0f, 0.0f);
|
||||
} else if (gDjuiCursorDownOn == base) {
|
||||
djui_base_set_border_color(base, 0, 84, 153, 255);
|
||||
djui_base_set_color(&entry->base, 204, 228, 247, 255);
|
||||
//djui_base_set_location(&entry->text->base, 1.0f, 1.0f);
|
||||
} else if (gDjuiHovered == base) {
|
||||
djui_base_set_border_color(base, 0, 120, 215, 255);
|
||||
djui_base_set_color(&entry->base, 229, 241, 251, 255);
|
||||
//djui_base_set_location(&entry->text->base, -1.0f, -1.0f);
|
||||
} else {
|
||||
u8 borderBrightness = 150;
|
||||
u8 rectBrightness = 222;
|
||||
djui_base_set_border_color(base, borderBrightness, borderBrightness, borderBrightness, 255);
|
||||
djui_base_set_color(&entry->base, rectBrightness, rectBrightness, rectBrightness, 255);
|
||||
//djui_base_set_location(&entry->text->base, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
static void djui_lobby_entry_destroy(struct DjuiBase* base) {
|
||||
struct DjuiLobbyEntry* lobbyEntry = (struct DjuiLobbyEntry*)base;
|
||||
if (lobbyEntry->description) { free((char*)lobbyEntry->description); }
|
||||
free(lobbyEntry);
|
||||
}
|
||||
|
||||
struct DjuiLobbyEntry* djui_lobby_entry_create(struct DjuiBase* parent, char* host, char* mode, char* players, char* description, void (*on_click)(struct DjuiBase*), void (*on_hover)(struct DjuiBase*), void (*on_hover_end)(struct DjuiBase*)) {
|
||||
struct DjuiLobbyEntry* lobbyEntry = calloc(1, sizeof(struct DjuiLobbyEntry));
|
||||
struct DjuiBase* base = &lobbyEntry->base;
|
||||
|
||||
lobbyEntry->description = strdup(description);
|
||||
|
||||
djui_base_init(parent, base, djui_rect_render, djui_lobby_entry_destroy);
|
||||
djui_base_set_size_type(&lobbyEntry->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&lobbyEntry->base, 1.0f, 32);
|
||||
djui_base_set_color(&lobbyEntry->base, 255, 255, 255, 128);
|
||||
djui_base_set_border_color(&lobbyEntry->base, 128, 128, 128, 255);
|
||||
djui_base_set_border_width(&lobbyEntry->base, 2);
|
||||
djui_base_set_border_width_type(&lobbyEntry->base, DJUI_SVT_ABSOLUTE);
|
||||
djui_interactable_create(base, djui_lobby_entry_update_style);
|
||||
djui_interactable_hook_click(base, on_click);
|
||||
djui_interactable_hook_hover(base, on_hover, on_hover_end);
|
||||
|
||||
u8 numColumns = 3;
|
||||
f32 x = 0;
|
||||
for (int i = 0; i < numColumns; i++) {
|
||||
char* msg = NULL;
|
||||
f32 width = 0;
|
||||
switch (i) {
|
||||
case 0: msg = host; width = 0.4f; break;
|
||||
case 1: msg = mode; width = 0.45f; break;
|
||||
case 2: msg = players; width = 0.15f; break;
|
||||
}
|
||||
struct DjuiText* text = djui_text_create(&lobbyEntry->base, msg);
|
||||
|
||||
djui_base_set_alignment(&text->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_CENTER);
|
||||
|
||||
djui_base_set_location_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
|
||||
djui_base_set_location(&text->base, x, 0.0f);
|
||||
|
||||
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
|
||||
djui_base_set_size(&text->base, width, 1.0f);
|
||||
|
||||
djui_base_set_color(&text->base, 11, 11, 11, 255);
|
||||
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
|
||||
djui_text_set_drop_shadow(text, 64, 64, 64, 100);
|
||||
x += width;
|
||||
}
|
||||
|
||||
djui_lobby_entry_update_style(base);
|
||||
|
||||
return lobbyEntry;
|
||||
}
|
9
src/pc/djui/djui_lobby_entry.h
Normal file
9
src/pc/djui/djui_lobby_entry.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include "djui.h"
|
||||
|
||||
struct DjuiLobbyEntry {
|
||||
struct DjuiBase base;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
struct DjuiLobbyEntry* djui_lobby_entry_create(struct DjuiBase* parent, char* host, char* mode, char* players, char* description, void (*on_click)(struct DjuiBase*), void (*on_hover)(struct DjuiBase*), void (*on_hover_end)(struct DjuiBase*));
|
|
@ -8,6 +8,10 @@
|
|||
// events //
|
||||
////////////
|
||||
|
||||
static struct DjuiButton* sPrevButton = NULL;
|
||||
static struct DjuiButton* sNextButton = NULL;
|
||||
static struct DjuiText* sPageNumText = NULL;
|
||||
|
||||
static s32 djui_paginated_get_count(struct DjuiPaginated* paginated) {
|
||||
s32 count = 0;
|
||||
struct DjuiBaseChild* dbc = paginated->layout->base.child;
|
||||
|
@ -19,35 +23,35 @@ static s32 djui_paginated_get_count(struct DjuiPaginated* paginated) {
|
|||
return count;
|
||||
}
|
||||
|
||||
static inline void djui_paginated_set_count_text(struct DjuiPaginated* paginated, s32 count) {
|
||||
void djui_paginated_update_page_buttons(struct DjuiPaginated* paginated) {
|
||||
s32 count = djui_paginated_get_count(paginated);
|
||||
char pageNumString[32] = { 0 };
|
||||
snprintf(pageNumString, 32, "%d/%d", paginated->startIndex / paginated->showCount + 1, count / paginated->showCount + 1);
|
||||
djui_text_set_text(paginated->pageNumText, pageNumString);
|
||||
djui_text_set_text(sPageNumText, pageNumString);
|
||||
djui_base_set_visible(&sPageNumText->base, (count > paginated->showCount));
|
||||
|
||||
djui_base_set_enabled(&sPrevButton->base, (paginated->startIndex > 0));
|
||||
djui_base_set_enabled(&sNextButton->base, ((paginated->startIndex + paginated->showCount) < count));
|
||||
}
|
||||
|
||||
static void djui_paginated_prev(struct DjuiBase* base) {
|
||||
struct DjuiPaginated* paginated = (struct DjuiPaginated*)base->parent;
|
||||
|
||||
paginated->startIndex -= paginated->showCount;
|
||||
|
||||
djui_base_set_enabled(&paginated->prevButton->base, (paginated->startIndex > 0));
|
||||
djui_base_set_enabled(&paginated->nextButton->base, true);
|
||||
|
||||
djui_paginated_set_count_text(paginated, djui_paginated_get_count(paginated));
|
||||
|
||||
if (paginated->startIndex < 0) { paginated->startIndex = 0; }
|
||||
|
||||
djui_paginated_update_page_buttons(paginated);
|
||||
}
|
||||
|
||||
static void djui_paginated_next(struct DjuiBase* base) {
|
||||
struct DjuiPaginated* paginated = (struct DjuiPaginated*)base->parent;
|
||||
paginated->startIndex += paginated->showCount;
|
||||
|
||||
s32 count = djui_paginated_get_count(paginated);
|
||||
|
||||
djui_base_set_enabled(&paginated->nextButton->base, (paginated->startIndex < count - 8));
|
||||
djui_base_set_enabled(&paginated->prevButton->base, true);
|
||||
|
||||
djui_paginated_set_count_text(paginated, count);
|
||||
|
||||
paginated->startIndex += paginated->showCount;
|
||||
if (paginated->startIndex >= count) { paginated->startIndex -= paginated->showCount; }
|
||||
|
||||
djui_paginated_update_page_buttons(paginated);
|
||||
|
||||
}
|
||||
|
||||
void djui_paginated_calculate_height(struct DjuiPaginated* paginated) {
|
||||
|
@ -71,18 +75,15 @@ void djui_paginated_calculate_height(struct DjuiPaginated* paginated) {
|
|||
if (count <= paginated->showCount) {
|
||||
djui_base_set_visible(&paginated->prevButton->base, false);
|
||||
djui_base_set_visible(&paginated->nextButton->base, false);
|
||||
djui_base_set_visible(&paginated->pageNumText->base, false);
|
||||
} else {
|
||||
djui_base_set_visible(&paginated->prevButton->base, true);
|
||||
djui_base_set_visible(&paginated->nextButton->base, true);
|
||||
djui_base_set_visible(&paginated->pageNumText->base, true);
|
||||
height += paginated->layout->margin.value;
|
||||
height += paginated->nextButton->base.height.value;
|
||||
}
|
||||
|
||||
djui_base_set_size(&paginated->base, paginated->base.width.value, height);
|
||||
|
||||
djui_paginated_set_count_text(paginated, count);
|
||||
djui_paginated_update_page_buttons(paginated);
|
||||
}
|
||||
|
||||
bool djui_paginated_render(struct DjuiBase* base) {
|
||||
|
@ -138,31 +139,25 @@ struct DjuiPaginated* djui_paginated_create(struct DjuiBase* parent, u32 showCou
|
|||
paginated->layout = layout;
|
||||
}
|
||||
|
||||
{
|
||||
struct DjuiButton* button = djui_button_create(&paginated->base, "<", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_prev);
|
||||
djui_base_set_alignment(&button->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
|
||||
djui_base_set_size_type(&button->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&button->base, 128, 32);
|
||||
djui_base_set_enabled(&button->base, false);
|
||||
paginated->prevButton = button;
|
||||
}
|
||||
sPrevButton = djui_button_create(&paginated->base, "<", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_prev);
|
||||
djui_base_set_alignment(&sPrevButton->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
|
||||
djui_base_set_size_type(&sPrevButton->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&sPrevButton->base, 128, 32);
|
||||
djui_base_set_enabled(&sPrevButton->base, false);
|
||||
paginated->prevButton = sPrevButton;
|
||||
|
||||
{
|
||||
struct DjuiText* text = djui_text_create(&paginated->base, "");
|
||||
djui_base_set_color(&text->base, 200, 200, 200, 255);
|
||||
djui_base_set_alignment(&text->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
|
||||
djui_base_set_size_type(&text->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
|
||||
text->base.y.value -= 30;
|
||||
paginated->pageNumText = text;
|
||||
}
|
||||
sPageNumText = djui_text_create(&paginated->base, "");
|
||||
djui_base_set_color(&sPageNumText->base, 200, 200, 200, 255);
|
||||
djui_base_set_alignment(&sPageNumText->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
|
||||
sPageNumText->base.y.value -= 30;
|
||||
|
||||
{
|
||||
struct DjuiButton* button = djui_button_create(&paginated->base, ">", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_next);
|
||||
djui_base_set_alignment(&button->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM);
|
||||
djui_base_set_size_type(&button->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&button->base, 128, 32);
|
||||
paginated->nextButton = button;
|
||||
}
|
||||
sNextButton = djui_button_create(&paginated->base, ">", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_next);
|
||||
djui_base_set_alignment(&sNextButton->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM);
|
||||
djui_base_set_size_type(&sNextButton->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&sNextButton->base, 128, 32);
|
||||
paginated->nextButton = sNextButton;
|
||||
|
||||
djui_paginated_update_page_buttons(paginated);
|
||||
|
||||
return paginated;
|
||||
}
|
||||
|
|
|
@ -11,5 +11,6 @@ struct DjuiPaginated {
|
|||
s32 showCount;
|
||||
};
|
||||
|
||||
void djui_paginated_update_page_buttons(struct DjuiPaginated* paginated);
|
||||
void djui_paginated_calculate_height(struct DjuiPaginated* paginated);
|
||||
struct DjuiPaginated* djui_paginated_create(struct DjuiBase* parent, u32 showCount);
|
||||
|
|
|
@ -12,16 +12,25 @@
|
|||
#include "pc/configfile.h"
|
||||
#include "pc/cheats.h"
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
#define DJUI_HOST_NS_IS_SOCKET (configNetworkSystem == 1)
|
||||
#else
|
||||
#define DJUI_HOST_NS_IS_SOCKET (true)
|
||||
#endif
|
||||
|
||||
struct DjuiRect* sRectPort = NULL;
|
||||
struct DjuiRect* sRectPassword = NULL;
|
||||
struct DjuiInputbox* sInputboxPort = NULL;
|
||||
struct DjuiInputbox* sInputboxPassword = NULL;
|
||||
|
||||
static void djui_panel_host_network_system_change(UNUSED struct DjuiBase* base) {
|
||||
djui_base_set_enabled(&sInputboxPort->base, DJUI_HOST_NS_IS_SOCKET);
|
||||
#ifndef COOPNET
|
||||
{
|
||||
struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*) base;
|
||||
if (*selectionbox->value == NS_COOPNET) {
|
||||
selectionbox->value = NS_SOCKET;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
djui_base_set_visible(&sRectPort->base, (configNetworkSystem == NS_SOCKET));
|
||||
djui_base_set_visible(&sRectPassword->base, (configNetworkSystem == NS_COOPNET));
|
||||
djui_base_set_enabled(&sInputboxPort->base, (configNetworkSystem == NS_SOCKET));
|
||||
djui_base_set_enabled(&sInputboxPassword->base, (configNetworkSystem == NS_COOPNET));
|
||||
}
|
||||
|
||||
static bool djui_panel_host_port_valid(void) {
|
||||
|
@ -41,11 +50,18 @@ static bool djui_panel_host_port_valid(void) {
|
|||
}
|
||||
|
||||
static void djui_panel_host_port_text_change(struct DjuiBase* caller) {
|
||||
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
|
||||
struct DjuiInputbox* sInputboxPort = (struct DjuiInputbox*)caller;
|
||||
if (djui_panel_host_port_valid()) {
|
||||
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
|
||||
djui_inputbox_set_text_color(sInputboxPort, 0, 0, 0, 255);
|
||||
} else {
|
||||
djui_inputbox_set_text_color(inputbox1, 255, 0, 0, 255);
|
||||
djui_inputbox_set_text_color(sInputboxPort, 255, 0, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
static void djui_panel_host_password_text_change(UNUSED struct DjuiBase* caller) {
|
||||
snprintf(configPassword, 64, "%s", sInputboxPassword->buffer);
|
||||
if (strlen(sInputboxPassword->buffer) >= 64) {
|
||||
djui_inputbox_set_text(sInputboxPassword, configPassword);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +81,10 @@ static void djui_panel_host_do_host(struct DjuiBase* caller) {
|
|||
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
network_rehost_begin();
|
||||
} else if (configNetworkSystem == NS_COOPNET) {
|
||||
extern void djui_panel_do_host(bool reconnecting);
|
||||
network_reset_reconnect_and_rehost();
|
||||
djui_panel_do_host(false);
|
||||
} else {
|
||||
djui_panel_host_message_create(caller);
|
||||
}
|
||||
|
@ -77,42 +97,70 @@ void djui_panel_host_create(struct DjuiBase* caller) {
|
|||
: DLANG(HOST, HOST_TITLE));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
#ifdef DISCORD_SDK
|
||||
char* nChoices[2] = { DLANG(HOST, DISCORD), DLANG(HOST, DIRECT_CONNECTION) };
|
||||
char* nChoices[] = { DLANG(HOST, DIRECT_CONNECTION), DLANG(HOST, COOPNET) };
|
||||
struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(body, DLANG(HOST, NETWORK_SYSTEM), nChoices, 2, &configNetworkSystem, djui_panel_host_network_system_change);
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_base_set_enabled(&selectionbox1->base, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct DjuiRect* rect1 = djui_rect_container_create(body, 32);
|
||||
{
|
||||
struct DjuiText* text1 = djui_text_create(&rect1->base, DLANG(HOST, PORT));
|
||||
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_color(&text1->base, 200, 200, 200, 255);
|
||||
djui_base_set_size(&text1->base, 0.585f, 64);
|
||||
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_base_set_enabled(&text1->base, false);
|
||||
sRectPort = djui_rect_container_create(&rect1->base, 32);
|
||||
djui_base_set_location(&sRectPort->base, 0, 0);
|
||||
djui_base_set_visible(&sRectPort->base, (configNetworkSystem == NS_SOCKET));
|
||||
{
|
||||
struct DjuiText* text1 = djui_text_create(&sRectPort->base, DLANG(HOST, PORT));
|
||||
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_color(&text1->base, 200, 200, 200, 255);
|
||||
djui_base_set_size(&text1->base, 0.585f, 64);
|
||||
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_base_set_enabled(&text1->base, false);
|
||||
}
|
||||
|
||||
sInputboxPort = djui_inputbox_create(&sRectPort->base, 32);
|
||||
djui_base_set_size_type(&sInputboxPort->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&sInputboxPort->base, 0.4f, 32);
|
||||
djui_base_set_alignment(&sInputboxPort->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
char portString[32] = { 0 };
|
||||
snprintf(portString, 32, "%d", configHostPort);
|
||||
djui_inputbox_set_text(sInputboxPort, portString);
|
||||
djui_interactable_hook_value_change(&sInputboxPort->base, djui_panel_host_port_text_change);
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_base_set_enabled(&sInputboxPort->base, false);
|
||||
} else {
|
||||
djui_base_set_enabled(&sInputboxPort->base, (configNetworkSystem == NS_SOCKET));
|
||||
}
|
||||
}
|
||||
|
||||
struct DjuiInputbox* inputbox1 = djui_inputbox_create(&rect1->base, 32);
|
||||
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&inputbox1->base, 0.4f, 32);
|
||||
djui_base_set_alignment(&inputbox1->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
char portString[32] = { 0 };
|
||||
snprintf(portString, 32, "%d", configHostPort);
|
||||
djui_inputbox_set_text(inputbox1, portString);
|
||||
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_host_port_text_change);
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_base_set_enabled(&inputbox1->base, false);
|
||||
#ifdef DISCORD_SDK
|
||||
} else {
|
||||
djui_base_set_enabled(&inputbox1->base, DJUI_HOST_NS_IS_SOCKET);
|
||||
#endif
|
||||
sRectPassword = djui_rect_container_create(&rect1->base, 32);
|
||||
djui_base_set_location(&sRectPassword->base, 0, 0);
|
||||
djui_base_set_visible(&sRectPassword->base, (configNetworkSystem == NS_COOPNET));
|
||||
{
|
||||
struct DjuiText* text1 = djui_text_create(&sRectPassword->base, DLANG(HOST, PASSWORD));
|
||||
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_color(&text1->base, 200, 200, 200, 255);
|
||||
djui_base_set_size(&text1->base, 0.585f, 64);
|
||||
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_base_set_enabled(&text1->base, false);
|
||||
}
|
||||
|
||||
sInputboxPassword = djui_inputbox_create(&sRectPassword->base, 32);
|
||||
sInputboxPassword->passwordChar[0] = '#';
|
||||
djui_base_set_size_type(&sInputboxPassword->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&sInputboxPassword->base, 0.4f, 32);
|
||||
djui_base_set_alignment(&sInputboxPassword->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
char portPassword[64] = { 0 };
|
||||
snprintf(portPassword, 64, "%s", configPassword);
|
||||
djui_inputbox_set_text(sInputboxPassword, portPassword);
|
||||
djui_interactable_hook_value_change(&sInputboxPassword->base, djui_panel_host_password_text_change);
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
djui_base_set_enabled(&sInputboxPassword->base, false);
|
||||
} else {
|
||||
djui_base_set_enabled(&sInputboxPassword->base, (configNetworkSystem == NS_COOPNET));
|
||||
}
|
||||
}
|
||||
sInputboxPort = inputbox1;
|
||||
}
|
||||
|
||||
struct DjuiRect* rect2 = djui_rect_container_create(body, 32);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "djui_panel_menu.h"
|
||||
#include "djui_panel_modlist.h"
|
||||
#include "src/pc/network/network.h"
|
||||
#include "src/pc/network/discord/discord.h"
|
||||
#include "src/pc/utils/misc.h"
|
||||
#include "src/pc/configfile.h"
|
||||
#include "pc/utils/misc.h"
|
||||
|
@ -14,25 +13,20 @@
|
|||
#include "audio/external.h"
|
||||
#include "sounds.h"
|
||||
|
||||
void djui_panel_do_host(void) {
|
||||
void djui_panel_do_host(bool reconnecting) {
|
||||
stop_demo(NULL);
|
||||
djui_panel_shutdown();
|
||||
extern s16 gCurrSaveFileNum;
|
||||
gCurrSaveFileNum = configHostSaveSlot;
|
||||
update_all_mario_stars();
|
||||
|
||||
#ifndef DISCORD_SDK
|
||||
configNetworkSystem = 1;
|
||||
network_set_system(NS_SOCKET);
|
||||
#else
|
||||
if (configNetworkSystem == 0) {
|
||||
network_set_system(NS_DISCORD);
|
||||
} else {
|
||||
network_set_system(NS_SOCKET);
|
||||
}
|
||||
#ifndef COOPNET
|
||||
if (configNetworkSystem == NS_COOPNET) { configNetworkSystem = NS_SOCKET; }
|
||||
#endif
|
||||
if (configNetworkSystem >= NS_MAX) { configNetworkSystem = NS_MAX; }
|
||||
network_set_system(configNetworkSystem);
|
||||
|
||||
network_init(NT_SERVER);
|
||||
network_init(NT_SERVER, reconnecting);
|
||||
djui_panel_modlist_create(NULL);
|
||||
fake_lvl_init_from_save_file();
|
||||
|
||||
|
@ -48,7 +42,7 @@ void djui_panel_do_host(void) {
|
|||
|
||||
void djui_panel_host_message_do_host(UNUSED struct DjuiBase* caller) {
|
||||
network_reset_reconnect_and_rehost();
|
||||
djui_panel_do_host();
|
||||
djui_panel_do_host(false);
|
||||
}
|
||||
|
||||
void djui_panel_host_message_create(struct DjuiBase* caller) {
|
||||
|
@ -56,18 +50,9 @@ void djui_panel_host_message_create(struct DjuiBase* caller) {
|
|||
char* warningMessage = NULL;
|
||||
bool hideHostButton = false;
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
if (!configNetworkSystem) {
|
||||
warningLines = gDiscordFailed ? 5 : 13;
|
||||
warningMessage = gDiscordFailed ? DLANG(HOST_MESSAGE, WARN_DISCORD2) : DLANG(HOST_MESSAGE, WARN_DISCORD);
|
||||
hideHostButton = gDiscordFailed;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
warningLines = 5;
|
||||
warningMessage = calloc(256, sizeof(char));
|
||||
sprintf(warningMessage, DLANG(HOST_MESSAGE, WARN_SOCKET), configHostPort);
|
||||
}
|
||||
warningLines = 5;
|
||||
warningMessage = calloc(256, sizeof(char));
|
||||
snprintf(warningMessage, 256, DLANG(HOST_MESSAGE, WARN_SOCKET), configHostPort);
|
||||
|
||||
f32 textHeight = 32 * 0.8125f * warningLines + 8;
|
||||
|
||||
|
@ -93,10 +78,5 @@ void djui_panel_host_message_create(struct DjuiBase* caller) {
|
|||
}
|
||||
|
||||
djui_panel_add(caller, panel, NULL);
|
||||
#ifdef DISCORD_SDK
|
||||
if (configNetworkSystem)
|
||||
#endif
|
||||
{
|
||||
free(warningMessage);
|
||||
}
|
||||
free(warningMessage);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "pc/utils/misc.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "pc/cheats.h"
|
||||
#include "pc/network/discord/lobby.h"
|
||||
#include "djui_inputbox.h"
|
||||
|
||||
static unsigned int sKnockbackIndex = 0;
|
||||
|
|
|
@ -1,202 +1,31 @@
|
|||
#include <stdio.h>
|
||||
#include "djui.h"
|
||||
#include "djui_panel.h"
|
||||
#include "djui_panel_menu.h"
|
||||
#include "djui_panel_join_message.h"
|
||||
#include "djui_panel_modlist.h"
|
||||
#include "src/pc/network/network.h"
|
||||
#include "src/pc/network/socket/socket.h"
|
||||
#include "src/pc/network/socket/domain_res.h"
|
||||
#include "src/pc/utils/misc.h"
|
||||
#include "src/pc/configfile.h"
|
||||
#include "src/pc/debuglog.h"
|
||||
#include "djui_panel_join_lobbies.h"
|
||||
#include "djui_panel_join_private.h"
|
||||
#include "djui_panel_join_direct.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/utils/misc.h"
|
||||
|
||||
static struct DjuiInputbox* sInputboxIp = NULL;
|
||||
|
||||
static bool djui_panel_join_ip_parse_numbers(char** msg) {
|
||||
int num = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
char c = **msg;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// is number
|
||||
num *= 10;
|
||||
num += (c - '0');
|
||||
*msg = *msg + 1;
|
||||
} else if (i == 0) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return num >= 0 && num <= 255;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_ip_parse_period(char** msg) {
|
||||
char c = **msg;
|
||||
bool isPeriod = (c == '.');
|
||||
if (isPeriod) { *msg = *msg + 1; }
|
||||
return isPeriod;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_ip_parse_spacer(char** msg) {
|
||||
char c = **msg;
|
||||
bool isSpacer = (c == ':' || c == ' ');
|
||||
if (isSpacer) { *msg = *msg + 1; }
|
||||
return isSpacer;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_ip_parse_port(char** msg) {
|
||||
int port = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
char c = **msg;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// is number
|
||||
port *= 10;
|
||||
port += (c - '0');
|
||||
*msg = *msg + 1;
|
||||
} else if (i == 0) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return port <= 65535;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_ip_valid(char* buffer) {
|
||||
char** msg = &buffer;
|
||||
|
||||
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
|
||||
if (!djui_panel_join_ip_parse_period(msg)) { return false; }
|
||||
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
|
||||
if (!djui_panel_join_ip_parse_period(msg)) { return false; }
|
||||
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
|
||||
if (!djui_panel_join_ip_parse_period(msg)) { return false; }
|
||||
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
|
||||
if (djui_panel_join_ip_parse_spacer(msg)) {
|
||||
if (!djui_panel_join_ip_parse_port(msg)) { return false; }
|
||||
}
|
||||
|
||||
return (**msg == '\0');
|
||||
}
|
||||
|
||||
static void djui_panel_join_ip_text_change(struct DjuiBase* caller) {
|
||||
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
|
||||
if (strlen(inputbox1->buffer) > 2) {
|
||||
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
|
||||
} else {
|
||||
djui_inputbox_set_text_color(inputbox1, 255, 0, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
static void djui_panel_join_ip_text_set_new(void) {
|
||||
char buffer[256] = { 0 };
|
||||
if (snprintf(buffer, 256, "%s", sInputboxIp->buffer) < 0) {
|
||||
LOG_INFO("truncating IP");
|
||||
}
|
||||
|
||||
bool afterSpacer = false;
|
||||
int port = 0;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (buffer[i] == ' ' || buffer[i] == ':') {
|
||||
buffer[i] = '\0';
|
||||
afterSpacer = true;
|
||||
} else if (buffer[i] == '\0') {
|
||||
break;
|
||||
} else if (afterSpacer && buffer[i] >= '0' && buffer[i] <= '9') {
|
||||
port *= 10;
|
||||
port += buffer[i] - '0';
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(gGetHostName, MAX_CONFIG_STRING, "%s", buffer);
|
||||
if (snprintf(configJoinIp, MAX_CONFIG_STRING, "%s", buffer) < 0) {
|
||||
LOG_INFO("truncating IP");
|
||||
}
|
||||
if (port >= 1 && port <= 65535) {
|
||||
configJoinPort = port;
|
||||
} else {
|
||||
configJoinPort = DEFAULT_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
static void djui_panel_join_ip_text_set(struct DjuiInputbox* inputbox1) {
|
||||
char buffer[256] = { 0 };
|
||||
if (strlen(configJoinIp) > 0 && configJoinPort != DEFAULT_PORT) {
|
||||
if (snprintf(buffer, 256, "%s:%d", configJoinIp, configJoinPort) < 0) { LOG_INFO("truncating IP"); }
|
||||
} else if (strlen(configJoinIp) > 0) {
|
||||
if (snprintf(buffer, 256, "%s", configJoinIp) < 0) { LOG_INFO("truncating IP"); }
|
||||
} else {
|
||||
if (snprintf(buffer, 256, "localhost") < 0) { LOG_INFO("truncating IP"); }
|
||||
}
|
||||
|
||||
djui_inputbox_set_text(inputbox1, buffer);
|
||||
}
|
||||
|
||||
void djui_panel_join_do_join(struct DjuiBase* caller) {
|
||||
if (!(strlen(sInputboxIp->buffer) > 2)) {
|
||||
djui_interactable_set_input_focus(&sInputboxIp->base);
|
||||
djui_inputbox_select_all(sInputboxIp);
|
||||
return;
|
||||
}
|
||||
network_reset_reconnect_and_rehost();
|
||||
djui_panel_join_ip_text_set_new();
|
||||
network_set_system(NS_SOCKET);
|
||||
network_init(NT_CLIENT);
|
||||
djui_panel_join_message_create(caller);
|
||||
#ifdef COOPNET
|
||||
static void djui_panel_join_public_lobbies(struct DjuiBase* caller) {
|
||||
djui_panel_join_lobbies_create(caller, "");
|
||||
}
|
||||
#endif
|
||||
|
||||
void djui_panel_join_create(struct DjuiBase* caller) {
|
||||
|
||||
struct DjuiBase* defaultBase = NULL;
|
||||
#ifndef COOPNET
|
||||
djui_panel_join_direct_create(caller);
|
||||
#else
|
||||
struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(JOIN, JOIN_TITLE));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
#ifdef DISCORD_SDK
|
||||
struct DjuiText* text1 = djui_text_create(body, DLANG(JOIN, JOIN_DISCORD));
|
||||
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&text1->base, 1.0f, 100);
|
||||
djui_base_compute_tree(&text1->base);
|
||||
u16 discordLines = djui_text_count_lines(text1, 12);
|
||||
f32 discordTextHeight = 32 * 0.8125f * discordLines + 8;
|
||||
djui_base_set_size(&text1->base, 1.0f, discordTextHeight);
|
||||
djui_base_set_color(&text1->base, 200, 200, 200, 255);
|
||||
#endif
|
||||
struct DjuiRect* rect1 = djui_rect_create(body);
|
||||
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&rect1->base, 1.0f, 2);
|
||||
djui_base_set_color(&rect1->base, 150, 150, 150, 255);
|
||||
|
||||
struct DjuiText* text2 = djui_text_create(body, DLANG(JOIN, JOIN_SOCKET));
|
||||
djui_base_set_size_type(&text2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&text2->base, 1.0f, 100);
|
||||
djui_base_compute_tree(&text2->base);
|
||||
u16 directLines = djui_text_count_lines(text2, 12);
|
||||
f32 directTextHeight = 32 * 0.8125f * directLines + 8;
|
||||
djui_base_set_size(&text2->base, 1.0f, directTextHeight);
|
||||
djui_base_set_color(&text2->base, 200, 200, 200, 255);
|
||||
|
||||
struct DjuiInputbox* inputbox1 = djui_inputbox_create(body, 256);
|
||||
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&inputbox1->base, 1.0f, 32.0f);
|
||||
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_join_ip_text_change);
|
||||
sInputboxIp = inputbox1;
|
||||
djui_panel_join_ip_text_set(inputbox1);
|
||||
|
||||
struct DjuiRect* rect2 = djui_rect_container_create(body, 64);
|
||||
{
|
||||
struct DjuiButton* button1 = djui_button_create(&rect2->base, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
|
||||
djui_base_set_size(&button1->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
|
||||
struct DjuiButton* button2 = djui_button_create(&rect2->base, DLANG(JOIN, JOIN), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_do_join);
|
||||
djui_base_set_size(&button2->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
defaultBase = &button2->base;
|
||||
}
|
||||
djui_button_create(body, DLANG(JOIN, PUBLIC_LOBBIES), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_public_lobbies);
|
||||
djui_button_create(body, DLANG(JOIN, PRIVATE_LOBBIES), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_private_create);
|
||||
djui_button_create(body, DLANG(JOIN, DIRECT), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_direct_create);
|
||||
djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
|
||||
}
|
||||
|
||||
djui_panel_add(caller, panel, defaultBase);
|
||||
djui_panel_add(caller, panel, NULL);
|
||||
#endif
|
||||
}
|
||||
|
|
189
src/pc/djui/djui_panel_join_direct.c
Normal file
189
src/pc/djui/djui_panel_join_direct.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
#include <stdio.h>
|
||||
#include "djui.h"
|
||||
#include "djui_panel.h"
|
||||
#include "djui_panel_menu.h"
|
||||
#include "djui_panel_modlist.h"
|
||||
#include "djui_panel_join_message.h"
|
||||
#include "djui_lobby_entry.h"
|
||||
#include "src/pc/network/network.h"
|
||||
#include "src/pc/network/socket/socket.h"
|
||||
#include "src/pc/network/coopnet/coopnet.h"
|
||||
#include "src/pc/network/socket/domain_res.h"
|
||||
#include "src/pc/utils/misc.h"
|
||||
#include "src/pc/configfile.h"
|
||||
#include "src/pc/debuglog.h"
|
||||
#include "macros.h"
|
||||
|
||||
static struct DjuiInputbox* sInputboxIp = NULL;
|
||||
|
||||
static bool djui_panel_join_direct_ip_parse_numbers(char** msg) {
|
||||
int num = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
char c = **msg;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// is number
|
||||
num *= 10;
|
||||
num += (c - '0');
|
||||
*msg = *msg + 1;
|
||||
} else if (i == 0) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return num >= 0 && num <= 255;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_direct_ip_parse_period(char** msg) {
|
||||
char c = **msg;
|
||||
bool isPeriod = (c == '.');
|
||||
if (isPeriod) { *msg = *msg + 1; }
|
||||
return isPeriod;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_direct_ip_parse_spacer(char** msg) {
|
||||
char c = **msg;
|
||||
bool isSpacer = (c == ':' || c == ' ');
|
||||
if (isSpacer) { *msg = *msg + 1; }
|
||||
return isSpacer;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_direct_ip_parse_port(char** msg) {
|
||||
int port = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
char c = **msg;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// is number
|
||||
port *= 10;
|
||||
port += (c - '0');
|
||||
*msg = *msg + 1;
|
||||
} else if (i == 0) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return port <= 65535;
|
||||
}
|
||||
|
||||
static bool djui_panel_join_direct_ip_valid(char* buffer) {
|
||||
char** msg = &buffer;
|
||||
|
||||
if (!djui_panel_join_direct_ip_parse_numbers(msg)) { return false; }
|
||||
if (!djui_panel_join_direct_ip_parse_period(msg)) { return false; }
|
||||
if (!djui_panel_join_direct_ip_parse_numbers(msg)) { return false; }
|
||||
if (!djui_panel_join_direct_ip_parse_period(msg)) { return false; }
|
||||
if (!djui_panel_join_direct_ip_parse_numbers(msg)) { return false; }
|
||||
if (!djui_panel_join_direct_ip_parse_period(msg)) { return false; }
|
||||
if (!djui_panel_join_direct_ip_parse_numbers(msg)) { return false; }
|
||||
if (djui_panel_join_direct_ip_parse_spacer(msg)) {
|
||||
if (!djui_panel_join_direct_ip_parse_port(msg)) { return false; }
|
||||
}
|
||||
|
||||
return (**msg == '\0');
|
||||
}
|
||||
|
||||
static void djui_panel_join_direct_ip_text_change(struct DjuiBase* caller) {
|
||||
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
|
||||
if (strlen(inputbox1->buffer) > 2) {
|
||||
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
|
||||
} else {
|
||||
djui_inputbox_set_text_color(inputbox1, 255, 0, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
static void djui_panel_join_direct_ip_text_set_new(void) {
|
||||
char buffer[256] = { 0 };
|
||||
if (snprintf(buffer, 256, "%s", sInputboxIp->buffer) < 0) {
|
||||
LOG_INFO("truncating IP");
|
||||
}
|
||||
|
||||
bool afterSpacer = false;
|
||||
int port = 0;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (buffer[i] == ' ' || buffer[i] == ':') {
|
||||
buffer[i] = '\0';
|
||||
afterSpacer = true;
|
||||
} else if (buffer[i] == '\0') {
|
||||
break;
|
||||
} else if (afterSpacer && buffer[i] >= '0' && buffer[i] <= '9') {
|
||||
port *= 10;
|
||||
port += buffer[i] - '0';
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(gGetHostName, MAX_CONFIG_STRING, "%s", buffer);
|
||||
if (snprintf(configJoinIp, MAX_CONFIG_STRING, "%s", buffer) < 0) {
|
||||
LOG_INFO("truncating IP");
|
||||
}
|
||||
if (port >= 1 && port <= 65535) {
|
||||
configJoinPort = port;
|
||||
} else {
|
||||
configJoinPort = DEFAULT_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
static void djui_panel_join_direct_ip_text_set(struct DjuiInputbox* inputbox1) {
|
||||
char buffer[256] = { 0 };
|
||||
if (strlen(configJoinIp) > 0 && configJoinPort != DEFAULT_PORT) {
|
||||
if (snprintf(buffer, 256, "%s:%d", configJoinIp, configJoinPort) < 0) { LOG_INFO("truncating IP"); }
|
||||
} else if (strlen(configJoinIp) > 0) {
|
||||
if (snprintf(buffer, 256, "%s", configJoinIp) < 0) { LOG_INFO("truncating IP"); }
|
||||
} else {
|
||||
if (snprintf(buffer, 256, "localhost") < 0) { LOG_INFO("truncating IP"); }
|
||||
}
|
||||
|
||||
djui_inputbox_set_text(inputbox1, buffer);
|
||||
}
|
||||
|
||||
void djui_panel_join_direct_do_join(struct DjuiBase* caller) {
|
||||
if (!(strlen(sInputboxIp->buffer) > 2)) {
|
||||
djui_interactable_set_input_focus(&sInputboxIp->base);
|
||||
djui_inputbox_select_all(sInputboxIp);
|
||||
return;
|
||||
}
|
||||
network_reset_reconnect_and_rehost();
|
||||
djui_panel_join_direct_ip_text_set_new();
|
||||
network_set_system(NS_SOCKET);
|
||||
network_init(NT_CLIENT, false);
|
||||
djui_panel_join_message_create(caller);
|
||||
}
|
||||
|
||||
void djui_panel_join_direct_create(struct DjuiBase* caller) {
|
||||
struct DjuiBase* defaultBase = NULL;
|
||||
struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(JOIN, JOIN_TITLE));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
struct DjuiText* text1 = djui_text_create(body, DLANG(JOIN, JOIN_SOCKET));
|
||||
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&text1->base, 1.0f, 100);
|
||||
djui_base_compute_tree(&text1->base);
|
||||
u16 directLines = djui_text_count_lines(text1, 12);
|
||||
f32 directTextHeight = 32 * 0.8125f * directLines + 8;
|
||||
djui_base_set_size(&text1->base, 1.0f, directTextHeight);
|
||||
djui_base_set_color(&text1->base, 200, 200, 200, 255);
|
||||
|
||||
struct DjuiInputbox* inputbox1 = djui_inputbox_create(body, 256);
|
||||
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&inputbox1->base, 1.0f, 32.0f);
|
||||
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_join_direct_ip_text_change);
|
||||
sInputboxIp = inputbox1;
|
||||
djui_panel_join_direct_ip_text_set(inputbox1);
|
||||
|
||||
struct DjuiRect* rect2 = djui_rect_container_create(body, 64);
|
||||
{
|
||||
struct DjuiButton* button1 = djui_button_create(&rect2->base, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
|
||||
djui_base_set_size(&button1->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
|
||||
struct DjuiButton* button2 = djui_button_create(&rect2->base, DLANG(JOIN, JOIN), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_direct_do_join);
|
||||
djui_base_set_size(&button2->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
defaultBase = &button2->base;
|
||||
}
|
||||
}
|
||||
|
||||
djui_panel_add(caller, panel, defaultBase);
|
||||
}
|
3
src/pc/djui/djui_panel_join_direct.h
Normal file
3
src/pc/djui/djui_panel_join_direct.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void djui_panel_join_direct_create(struct DjuiBase* caller);
|
173
src/pc/djui/djui_panel_join_lobbies.c
Normal file
173
src/pc/djui/djui_panel_join_lobbies.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
#include <stdio.h>
|
||||
#include "djui.h"
|
||||
#include "djui_panel.h"
|
||||
#include "djui_panel_menu.h"
|
||||
#include "djui_panel_join_message.h"
|
||||
#include "djui_lobby_entry.h"
|
||||
#include "src/pc/network/network.h"
|
||||
#include "src/pc/network/socket/socket.h"
|
||||
#include "src/pc/network/coopnet/coopnet.h"
|
||||
#include "src/pc/utils/misc.h"
|
||||
#include "src/pc/configfile.h"
|
||||
#include "src/pc/debuglog.h"
|
||||
#include "macros.h"
|
||||
|
||||
#ifdef COOPNET
|
||||
|
||||
#define DJUI_DESC_PANEL_WIDTH (410.0f + (16 * 2.0f))
|
||||
|
||||
static struct DjuiPaginated* sLobbyPaginated = NULL;
|
||||
static struct DjuiFlowLayout* sLobbyLayout = NULL;
|
||||
static struct DjuiButton* sRefreshButton = NULL;
|
||||
static struct DjuiThreePanel* sDescriptionPanel = NULL;
|
||||
static struct DjuiText* sTooltip = NULL;
|
||||
static char* sPassword = NULL;
|
||||
|
||||
static void djui_panel_join_lobby_description_create() {
|
||||
f32 bodyHeight = 600;
|
||||
|
||||
struct DjuiThreePanel* panel = djui_three_panel_create(&gDjuiRoot->base, 64, bodyHeight, 0);
|
||||
|
||||
djui_base_set_alignment(&panel->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_CENTER);
|
||||
djui_base_set_size_type(&panel->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE);
|
||||
djui_base_set_size(&panel->base, DJUI_DESC_PANEL_WIDTH, 1.0f);
|
||||
djui_base_set_color(&panel->base, 0, 0, 0, 240);
|
||||
djui_base_set_border_color(&panel->base, 0, 0, 0, 200);
|
||||
djui_base_set_border_width(&panel->base, 8);
|
||||
djui_base_set_padding(&panel->base, 16, 16, 16, 16);
|
||||
{
|
||||
struct DjuiFlowLayout* body = djui_flow_layout_create(&panel->base);
|
||||
djui_base_set_alignment(&body->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
|
||||
djui_base_set_size_type(&body->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
|
||||
djui_base_set_size(&body->base, 1.0f, 1.0f);
|
||||
djui_base_set_color(&body->base, 0, 0, 0, 0);
|
||||
djui_flow_layout_set_margin(body, 16);
|
||||
djui_flow_layout_set_flow_direction(body, DJUI_FLOW_DIR_DOWN);
|
||||
|
||||
struct DjuiText* description = djui_text_create(&panel->base, "");
|
||||
djui_base_set_size_type(&description->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
|
||||
djui_base_set_size(&description->base, 1.0f, 1.0f);
|
||||
djui_base_set_color(&description->base, 222, 222, 222, 255);
|
||||
djui_text_set_alignment(description, DJUI_HALIGN_LEFT, DJUI_VALIGN_CENTER);
|
||||
sTooltip = description;
|
||||
}
|
||||
sDescriptionPanel = panel;
|
||||
}
|
||||
|
||||
static void djui_lobby_on_hover(struct DjuiBase* base) {
|
||||
struct DjuiLobbyEntry* entry = (struct DjuiLobbyEntry*)base;
|
||||
djui_text_set_text(sTooltip, entry->description);
|
||||
}
|
||||
|
||||
static void djui_lobby_on_hover_end(UNUSED struct DjuiBase* base) {
|
||||
djui_text_set_text(sTooltip, "");
|
||||
}
|
||||
|
||||
void djui_panel_join_lobby(struct DjuiBase* caller) {
|
||||
gCoopNetDesiredLobby = (uint64_t)caller->tag;
|
||||
snprintf(gCoopNetPassword, 64, "%s", sPassword);
|
||||
network_reset_reconnect_and_rehost();
|
||||
network_set_system(NS_COOPNET);
|
||||
network_init(NT_CLIENT, false);
|
||||
djui_panel_join_message_create(caller);
|
||||
}
|
||||
|
||||
void djui_panel_join_query(uint64_t aLobbyId, UNUSED uint64_t aOwnerId, uint16_t aConnections, uint16_t aMaxConnections, UNUSED const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, const char* aDescription) {
|
||||
if (!sLobbyLayout) { return; }
|
||||
|
||||
char playerText[64] = "";
|
||||
snprintf(playerText, 63, "%u/%u", aConnections, aMaxConnections);
|
||||
|
||||
|
||||
char mode[64] = "";
|
||||
snprintf(mode, 64, "%s", aMode);
|
||||
|
||||
char version[MAX_VERSION_LENGTH] = { 0 };
|
||||
snprintf(version, MAX_VERSION_LENGTH, "%s", get_version());
|
||||
if (strcmp(version, aVersion) != 0) {
|
||||
snprintf(mode, 64, "\\#ff0000\\[%s]", aVersion);
|
||||
}
|
||||
|
||||
struct DjuiBase* layoutBase = &sLobbyLayout->base;
|
||||
struct DjuiLobbyEntry* entry = djui_lobby_entry_create(layoutBase, (char*)aHostName, (char*)mode, playerText, (char*)aDescription, djui_panel_join_lobby, djui_lobby_on_hover, djui_lobby_on_hover_end);
|
||||
entry->base.tag = (s64)aLobbyId;
|
||||
djui_paginated_update_page_buttons(sLobbyPaginated);
|
||||
}
|
||||
|
||||
void djui_panel_join_query_finish(void) {
|
||||
if (!sRefreshButton) { return; }
|
||||
djui_text_set_text(sRefreshButton->text, DLANG(LOBBIES, REFRESH));
|
||||
djui_base_set_enabled(&sRefreshButton->base, true);
|
||||
|
||||
if (sLobbyLayout->base.child == NULL) {
|
||||
struct DjuiText* text = djui_text_create(&sLobbyLayout->base, DLANG(LOBBIES, NONE_FOUND));
|
||||
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
|
||||
djui_base_set_size(&text->base, 1, 1);
|
||||
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
|
||||
}
|
||||
djui_paginated_update_page_buttons(sLobbyPaginated);
|
||||
}
|
||||
|
||||
void djui_panel_join_lobbies_on_destroy(UNUSED struct DjuiBase* caller) {
|
||||
if (sPassword) { free(sPassword); }
|
||||
sPassword = NULL;
|
||||
sRefreshButton = NULL;
|
||||
sLobbyLayout = NULL;
|
||||
sLobbyPaginated = NULL;
|
||||
|
||||
if (sDescriptionPanel != NULL) {
|
||||
djui_base_destroy(&sDescriptionPanel->base);
|
||||
sDescriptionPanel = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void djui_panel_join_lobbies_refresh(UNUSED struct DjuiBase* caller) {
|
||||
djui_base_destroy_children(&sLobbyLayout->base);
|
||||
djui_text_set_text(sRefreshButton->text, DLANG(LOBBIES, REFRESHING));
|
||||
djui_base_set_enabled(&sRefreshButton->base, false);
|
||||
djui_paginated_update_page_buttons(sLobbyPaginated);
|
||||
ns_coopnet_query(djui_panel_join_query, djui_panel_join_query_finish, sPassword);
|
||||
}
|
||||
|
||||
void djui_panel_join_lobbies_create(struct DjuiBase* caller, const char* password) {
|
||||
if (sPassword) { free(sPassword); sPassword = NULL; }
|
||||
sPassword = strdup(password);
|
||||
bool private = (strlen(password) > 0);
|
||||
|
||||
djui_panel_join_lobby_description_create();
|
||||
|
||||
struct DjuiBase* defaultBase = NULL;
|
||||
struct DjuiThreePanel* panel = djui_panel_menu_create(private ? DLANG(LOBBIES, PRIVATE_LOBBIES) : DLANG(LOBBIES, PUBLIC_LOBBIES));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
sLobbyPaginated = djui_paginated_create(body, 8);
|
||||
sLobbyLayout = sLobbyPaginated->layout;
|
||||
djui_flow_layout_set_margin(sLobbyLayout, 4);
|
||||
|
||||
bool querying = ns_coopnet_query(djui_panel_join_query, djui_panel_join_query_finish, password);
|
||||
if (!querying) {
|
||||
struct DjuiText* text = djui_text_create(&sLobbyLayout->base, DLANG(NOTIF, COOPNET_CONNECTION_FAILED));
|
||||
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
|
||||
djui_base_set_size(&text->base, 1, 1);
|
||||
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
|
||||
}
|
||||
|
||||
struct DjuiRect* rect2 = djui_rect_container_create(body, 64);
|
||||
{
|
||||
struct DjuiButton* button1 = djui_button_create(&rect2->base, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
|
||||
djui_base_set_size(&button1->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
|
||||
sRefreshButton = djui_button_create(&rect2->base, querying ? DLANG(LOBBIES, REFRESHING) : DLANG(LOBBIES, REFRESH), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_lobbies_refresh);
|
||||
djui_base_set_size(&sRefreshButton->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&sRefreshButton->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
djui_base_set_enabled(&sRefreshButton->base, false);
|
||||
defaultBase = &sRefreshButton->base;
|
||||
}
|
||||
}
|
||||
|
||||
struct DjuiPanel* p = djui_panel_add(caller, panel, defaultBase);
|
||||
p->on_panel_destroy = djui_panel_join_lobbies_on_destroy;
|
||||
}
|
||||
|
||||
#endif
|
3
src/pc/djui/djui_panel_join_lobbies.h
Normal file
3
src/pc/djui/djui_panel_join_lobbies.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void djui_panel_join_lobbies_create(struct DjuiBase* caller, const char* password);
|
|
@ -22,7 +22,7 @@ void djui_panel_join_message_error(char* message) {
|
|||
void djui_panel_join_message_cancel(struct DjuiBase* caller) {
|
||||
if (network_is_reconnecting()) { return; }
|
||||
network_reset_reconnect_and_rehost();
|
||||
network_shutdown(true, false, false);
|
||||
network_shutdown(true, false, false, false);
|
||||
djui_panel_menu_back(caller);
|
||||
}
|
||||
|
||||
|
|
54
src/pc/djui/djui_panel_join_private.c
Normal file
54
src/pc/djui/djui_panel_join_private.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "djui.h"
|
||||
#include "djui_panel.h"
|
||||
#include "djui_panel_menu.h"
|
||||
#include "djui_panel_join_lobbies.h"
|
||||
#include "djui_panel_join_private.h"
|
||||
#include "djui_panel_join_direct.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/utils/misc.h"
|
||||
|
||||
#ifdef COOPNET
|
||||
|
||||
static struct DjuiInputbox* sInputboxPassword = NULL;
|
||||
|
||||
static void djui_panel_join_private_lobbies(struct DjuiBase* caller) {
|
||||
djui_panel_join_lobbies_create(caller, sInputboxPassword->buffer);
|
||||
}
|
||||
|
||||
void djui_panel_join_private_create(struct DjuiBase* caller) {
|
||||
struct DjuiBase* defaultBase = NULL;
|
||||
struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(LOBBIES, PRIVATE_LOBBIES));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
struct DjuiText* text1 = djui_text_create(body, DLANG(LOBBIES, ENTER_PASSWORD));
|
||||
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&text1->base, 1.0f, 100);
|
||||
djui_base_compute_tree(&text1->base);
|
||||
u16 directLines = djui_text_count_lines(text1, 12);
|
||||
f32 directTextHeight = 32 * 0.8125f * directLines + 8;
|
||||
djui_base_set_size(&text1->base, 1.0f, directTextHeight);
|
||||
djui_base_set_color(&text1->base, 200, 200, 200, 255);
|
||||
|
||||
struct DjuiInputbox* inputbox1 = djui_inputbox_create(body, 256);
|
||||
inputbox1->passwordChar[0] = '#';
|
||||
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&inputbox1->base, 1.0f, 32.0f);
|
||||
sInputboxPassword = inputbox1;
|
||||
|
||||
struct DjuiRect* rect2 = djui_rect_container_create(body, 64);
|
||||
{
|
||||
struct DjuiButton* button1 = djui_button_create(&rect2->base, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
|
||||
djui_base_set_size(&button1->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
|
||||
struct DjuiButton* button2 = djui_button_create(&rect2->base, DLANG(LOBBIES, SEARCH), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_private_lobbies);
|
||||
djui_base_set_size(&button2->base, 0.485f, 64);
|
||||
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
defaultBase = &button2->base;
|
||||
}
|
||||
}
|
||||
|
||||
djui_panel_add(caller, panel, defaultBase);
|
||||
}
|
||||
|
||||
#endif
|
3
src/pc/djui/djui_panel_join_private.h
Normal file
3
src/pc/djui/djui_panel_join_private.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void djui_panel_join_private_create(struct DjuiBase* caller);
|
|
@ -22,7 +22,7 @@ static void djui_panel_pause_resume(UNUSED struct DjuiBase* caller) {
|
|||
|
||||
static void djui_panel_pause_quit_yes(UNUSED struct DjuiBase* caller) {
|
||||
network_reset_reconnect_and_rehost();
|
||||
network_shutdown(true, false, false);
|
||||
network_shutdown(true, false, false, false);
|
||||
}
|
||||
|
||||
static void djui_panel_pause_quit(struct DjuiBase* caller) {
|
||||
|
|
|
@ -196,6 +196,7 @@ static void djui_panel_player_name_on_focus_end(struct DjuiBase* caller) {
|
|||
if (gNetworkType != NT_NONE) {
|
||||
network_send_player_settings();
|
||||
}
|
||||
djui_inputbox_on_focus_end(&inputbox1->base);
|
||||
}
|
||||
|
||||
static void djui_panel_player_value_changed(UNUSED struct DjuiBase* caller) {
|
||||
|
@ -255,7 +256,7 @@ void djui_panel_player_create(struct DjuiBase* caller) {
|
|||
djui_inputbox_set_text(inputbox1, DLANG(PLAYER, PLAYER));
|
||||
}
|
||||
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_player_name_text_change);
|
||||
djui_interactable_hook_focus(&inputbox1->base, NULL, NULL, djui_panel_player_name_on_focus_end);
|
||||
djui_interactable_hook_focus(&inputbox1->base, djui_inputbox_on_focus_begin, NULL, djui_panel_player_name_on_focus_end);
|
||||
}
|
||||
|
||||
char* modelChoices[CT_MAX] = { 0 };
|
||||
|
|
|
@ -1887,13 +1887,14 @@ static struct LuaObjectField sRayIntersectionInfoFields[LUA_RAY_INTERSECTION_INF
|
|||
{ "surface", LVT_COBJECT_P, offsetof(struct RayIntersectionInfo, surface), false, LOT_SURFACE },
|
||||
};
|
||||
|
||||
#define LUA_SERVER_SETTINGS_FIELD_COUNT 10
|
||||
#define LUA_SERVER_SETTINGS_FIELD_COUNT 11
|
||||
static struct LuaObjectField sServerSettingsFields[LUA_SERVER_SETTINGS_FIELD_COUNT] = {
|
||||
{ "bubbleDeath", LVT_U8, offsetof(struct ServerSettings, bubbleDeath), false, LOT_NONE },
|
||||
{ "enableCheats", LVT_U8, offsetof(struct ServerSettings, enableCheats), false, LOT_NONE },
|
||||
{ "enablePlayerList", LVT_U8, offsetof(struct ServerSettings, enablePlayerList), false, LOT_NONE },
|
||||
{ "enablePlayersInLevelDisplay", LVT_U8, offsetof(struct ServerSettings, enablePlayersInLevelDisplay), false, LOT_NONE },
|
||||
{ "headlessServer", LVT_U8, offsetof(struct ServerSettings, headlessServer), false, LOT_NONE },
|
||||
{ "maxPlayers", LVT_U8, offsetof(struct ServerSettings, maxPlayers), false, LOT_NONE },
|
||||
{ "playerInteractions", LVT_S32, offsetof(struct ServerSettings, playerInteractions), false, LOT_NONE },
|
||||
{ "playerKnockbackStrength", LVT_U8, offsetof(struct ServerSettings, playerKnockbackStrength), false, LOT_NONE },
|
||||
{ "shareLives", LVT_U8, offsetof(struct ServerSettings, shareLives), false, LOT_NONE },
|
||||
|
|
|
@ -1759,7 +1759,8 @@ char gSmluaConstants[] = ""
|
|||
"SYNC_DISTANCE_INFINITE = 0\n"
|
||||
"PACKET_LENGTH = 3000\n"
|
||||
"NS_SOCKET = 0\n"
|
||||
"NS_DISCORD = 1\n"
|
||||
"NS_COOPNET = 1\n"
|
||||
"NS_MAX = 2\n"
|
||||
"PLAYER_INTERACTIONS_NONE = 0\n"
|
||||
"PLAYER_INTERACTIONS_SOLID = 1\n"
|
||||
"PLAYER_INTERACTIONS_PVP = 2\n"
|
||||
|
@ -1767,7 +1768,7 @@ char gSmluaConstants[] = ""
|
|||
"UNKNOWN_GLOBAL_INDEX = (-1)\n"
|
||||
"UNKNOWN_NETWORK_INDEX = (-1)\n"
|
||||
"NETWORK_PLAYER_TIMEOUT = 10\n"
|
||||
"NETWORK_PLAYER_PING_TIMEOUT = 1\n"
|
||||
"NETWORK_PLAYER_PING_TIMEOUT = 3\n"
|
||||
"MAX_RX_SEQ_IDS = 64\n"
|
||||
"USE_REAL_PALETTE_VAR = 0xFF\n"
|
||||
"NPT_UNKNOWN = 0\n"
|
||||
|
@ -4015,8 +4016,8 @@ char gSmluaConstants[] = ""
|
|||
"COOP_OBJ_FLAG_NON_SYNC = (1 << 2)\n"
|
||||
"COOP_OBJ_FLAG_INITIALIZED = (1 << 3)\n"
|
||||
"VERSION_TEXT = 'beta'\n"
|
||||
"VERSION_NUMBER = 33\n"
|
||||
"MINOR_VERSION_NUMBER = 1\n"
|
||||
"VERSION_NUMBER = 34\n"
|
||||
"MINOR_VERSION_NUMBER = 0\n"
|
||||
"PATCH_VERSION_NUMBER = 0\n"
|
||||
"MAX_VERSION_LENGTH = 10\n"
|
||||
"MAX_LOCAL_VERSION_LENGTH = 12\n"
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "src/pc/lua/utils/smlua_text_utils.h"
|
||||
#include "src/pc/lua/utils/smlua_audio_utils.h"
|
||||
#include "src/pc/lua/utils/smlua_level_utils.h"
|
||||
#include "src/pc/lua/utils/smlua_deprecated.h"
|
||||
#include "src/game/object_list_processor.h"
|
||||
#include "src/game/behavior_actions.h"
|
||||
#include "src/game/mario_misc.h"
|
||||
|
@ -18741,23 +18742,6 @@ int smlua_func_network_player_set_description(lua_State* L) {
|
|||
// network_utils.h //
|
||||
/////////////////////
|
||||
|
||||
int smlua_func_network_discord_id_from_local_index(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 1) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_discord_id_from_local_index", 1, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 localIndex = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "network_discord_id_from_local_index"); return 0; }
|
||||
|
||||
lua_pushstring(L, network_discord_id_from_local_index(localIndex));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_get_player_text_color_string(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
|
@ -26273,6 +26257,27 @@ int smlua_func_smlua_collision_util_get(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// smlua_deprecated.h //
|
||||
////////////////////////
|
||||
|
||||
int smlua_func_network_discord_id_from_local_index(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 1) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_discord_id_from_local_index", 1, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 localIndex = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "network_discord_id_from_local_index"); return 0; }
|
||||
|
||||
lua_pushstring(L, network_discord_id_from_local_index(localIndex));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// smlua_level_utils.h //
|
||||
/////////////////////////
|
||||
|
@ -30186,7 +30191,6 @@ void smlua_bind_functions_autogen(void) {
|
|||
smlua_bind_function(L, "network_player_set_description", smlua_func_network_player_set_description);
|
||||
|
||||
// network_utils.h
|
||||
smlua_bind_function(L, "network_discord_id_from_local_index", smlua_func_network_discord_id_from_local_index);
|
||||
smlua_bind_function(L, "network_get_player_text_color_string", smlua_func_network_get_player_text_color_string);
|
||||
smlua_bind_function(L, "network_global_index_from_local", smlua_func_network_global_index_from_local);
|
||||
smlua_bind_function(L, "network_is_moderator", smlua_func_network_is_moderator);
|
||||
|
@ -30571,6 +30575,9 @@ void smlua_bind_functions_autogen(void) {
|
|||
smlua_bind_function(L, "get_water_surface_pseudo_floor", smlua_func_get_water_surface_pseudo_floor);
|
||||
smlua_bind_function(L, "smlua_collision_util_get", smlua_func_smlua_collision_util_get);
|
||||
|
||||
// smlua_deprecated.h
|
||||
smlua_bind_function(L, "network_discord_id_from_local_index", smlua_func_network_discord_id_from_local_index);
|
||||
|
||||
// smlua_level_utils.h
|
||||
smlua_bind_function(L, "level_register", smlua_func_level_register);
|
||||
smlua_bind_function(L, "smlua_level_util_get_info", smlua_func_smlua_level_util_get_info);
|
||||
|
|
15
src/pc/lua/utils/smlua_deprecated.c
Normal file
15
src/pc/lua/utils/smlua_deprecated.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "types.h"
|
||||
#ifdef DISCORD_SDK
|
||||
#include "pc/discord/discord.h"
|
||||
#endif
|
||||
|
||||
char* network_discord_id_from_local_index(u8 localIndex) {
|
||||
#ifdef DISCORD_SDK
|
||||
static char sDiscordId[64] = "";
|
||||
if (localIndex == 0) {
|
||||
snprintf(sDiscordId, 64, "%" PRIu64 "", (uint64_t)discord_get_user_id());
|
||||
return sDiscordId;
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
3
src/pc/lua/utils/smlua_deprecated.h
Normal file
3
src/pc/lua/utils/smlua_deprecated.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
char* network_discord_id_from_local_index(u8 localIndex);
|
|
@ -7,6 +7,19 @@
|
|||
#include "pc/utils/md5.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
size_t mod_get_lua_size(struct Mod* mod) {
|
||||
if (!mod) { return 0; }
|
||||
size_t size = 0;
|
||||
|
||||
for (int i = 0; i < mod->fileCount; i++) {
|
||||
struct ModFile* file = &mod->files[i];
|
||||
if (!str_ends_with(file->relativePath, ".lua")) { continue; }
|
||||
size += file->size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void mod_activate_bin(struct ModFile* file) {
|
||||
// copy geo name
|
||||
char geoName[64] = { 0 };
|
||||
|
|
|
@ -37,6 +37,7 @@ struct Mod {
|
|||
u8 customBehaviorIndex;
|
||||
};
|
||||
|
||||
size_t mod_get_lua_size(struct Mod* mod);
|
||||
void mod_activate(struct Mod* mod);
|
||||
void mod_clear(struct Mod* mod);
|
||||
bool mod_load(struct Mods* mods, char* basePath, char* modName);
|
||||
|
|
|
@ -20,6 +20,23 @@ struct LocalEnabledPath {
|
|||
|
||||
struct LocalEnabledPath* sLocalEnabledPaths = NULL;
|
||||
|
||||
void mods_get_main_mod_name(char* destination, u32 maxSize) {
|
||||
struct Mod* picked = NULL;
|
||||
size_t pickedSize = 0;
|
||||
|
||||
for (unsigned int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
if (!mod->enabled) { continue; }
|
||||
size_t size = mod_get_lua_size(mod);
|
||||
if (size > pickedSize) {
|
||||
picked = mod;
|
||||
pickedSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(destination, maxSize, "%s", picked ? picked->name : "Super Mario 64");
|
||||
}
|
||||
|
||||
static void mods_local_store_enabled(void) {
|
||||
assert(sLocalEnabledPaths == NULL);
|
||||
struct LocalEnabledPath* prev = NULL;
|
||||
|
|
|
@ -22,6 +22,7 @@ extern struct Mods gActiveMods;
|
|||
|
||||
extern char gRemoteModsBasePath[];
|
||||
|
||||
void mods_get_main_mod_name(char* destination, u32 maxSize);
|
||||
bool mods_generate_remote_base_path(void);
|
||||
void mods_activate(struct Mods* mods);
|
||||
void mods_clear(struct Mods* mods);
|
||||
|
|
293
src/pc/network/coopnet/coopnet.c
Normal file
293
src/pc/network/coopnet/coopnet.c
Normal file
|
@ -0,0 +1,293 @@
|
|||
#include "libcoopnet.h"
|
||||
#include "coopnet.h"
|
||||
#include "coopnet_id.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/network/version.h"
|
||||
#include "pc/djui/djui_language.h"
|
||||
#include "pc/djui/djui_popup.h"
|
||||
#include "pc/mods/mods.h"
|
||||
#include "pc/utils/misc.h"
|
||||
#include "pc/debuglog.h"
|
||||
#ifdef DISCORD_SDK
|
||||
#include "pc/discord/discord.h"
|
||||
#endif
|
||||
|
||||
#ifdef COOPNET
|
||||
|
||||
#define CN_GAME_STR "sm64ex-coop"
|
||||
|
||||
uint64_t gCoopNetDesiredLobby = 0;
|
||||
char gCoopNetPassword[64] = "";
|
||||
char sCoopNetDescription[256] = "";
|
||||
|
||||
static uint64_t sLocalLobbyId = 0;
|
||||
static uint64_t sLocalLobbyOwnerId = 0;
|
||||
static enum NetworkType sNetworkType;
|
||||
static bool sReconnecting = false;
|
||||
|
||||
static CoopNetRc coopnet_initialize(void);
|
||||
|
||||
bool ns_coopnet_query(QueryCallbackPtr callback, QueryFinishCallbackPtr finishCallback, const char* password) {
|
||||
gCoopNetCallbacks.OnLobbyListGot = callback;
|
||||
gCoopNetCallbacks.OnLobbyListFinish = finishCallback;
|
||||
if (coopnet_initialize() != COOPNET_OK) { return false; }
|
||||
if (coopnet_lobby_list_get(CN_GAME_STR, password) != COOPNET_OK) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
static void coopnet_on_connected(uint64_t userId) {
|
||||
coopnet_set_local_user_id(userId);
|
||||
}
|
||||
|
||||
static void coopnet_on_disconnected(bool intentional) {
|
||||
LOG_INFO("Coopnet shutdown!");
|
||||
if (!intentional) {
|
||||
djui_popup_create(DLANG(NOTIF, COOPNET_DISCONNECTED), 2);
|
||||
}
|
||||
coopnet_shutdown();
|
||||
gCoopNetCallbacks.OnLobbyListGot = NULL;
|
||||
gCoopNetCallbacks.OnLobbyListFinish = NULL;
|
||||
}
|
||||
|
||||
static void coopnet_on_peer_disconnected(uint64_t peerId) {
|
||||
u8 localIndex = coopnet_user_id_to_local_index(peerId);
|
||||
if (localIndex != UNKNOWN_LOCAL_INDEX && gNetworkPlayers[localIndex].connected) {
|
||||
network_player_disconnected(gNetworkPlayers[localIndex].globalIndex);
|
||||
}
|
||||
}
|
||||
|
||||
static void coopnet_on_receive(uint64_t userId, const uint8_t* data, uint64_t dataLength) {
|
||||
coopnet_set_user_id(0, userId);
|
||||
u8 localIndex = coopnet_user_id_to_local_index(userId);
|
||||
network_receive(localIndex, &userId, (u8*)data, dataLength);
|
||||
}
|
||||
|
||||
static void coopnet_on_lobby_joined(uint64_t lobbyId, uint64_t userId, uint64_t ownerId, uint64_t destId) {
|
||||
LOG_INFO("coopnet_on_lobby_joined!");
|
||||
coopnet_set_user_id(0, ownerId);
|
||||
sLocalLobbyId = lobbyId;
|
||||
sLocalLobbyOwnerId = ownerId;
|
||||
|
||||
if (userId == coopnet_get_local_user_id()) {
|
||||
coopnet_clear_dest_ids();
|
||||
}
|
||||
|
||||
coopnet_save_dest_id(userId, destId);
|
||||
|
||||
if (userId == coopnet_get_local_user_id() && gNetworkType == NT_CLIENT) {
|
||||
network_send_mod_list_request();
|
||||
}
|
||||
#ifdef DISCORD_SDK
|
||||
discord_activity_update();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void coopnet_on_lobby_left(uint64_t lobbyId, uint64_t userId) {
|
||||
LOG_INFO("coopnet_on_lobby_left!");
|
||||
coopnet_clear_dest_id(userId);
|
||||
if (lobbyId == sLocalLobbyId && userId == coopnet_get_local_user_id()) {
|
||||
network_shutdown(false, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void coopnet_on_error(enum MPacketErrorNumber error, uint64_t tag) {
|
||||
switch (error) {
|
||||
case MERR_COOPNET_VERSION:
|
||||
djui_popup_create(DLANG(NOTIF, COOPNET_VERSION), 2);
|
||||
network_shutdown(false, false, false, false);
|
||||
break;
|
||||
case MERR_PEER_FAILED:
|
||||
{
|
||||
char built[256] = { 0 };
|
||||
u8 localIndex = coopnet_user_id_to_local_index(tag);
|
||||
char* name = DLANG(NOTIF, UNKNOWN);
|
||||
if (localIndex == 0) {
|
||||
name = DLANG(NOTIF, LOBBY_HOST);
|
||||
} else if (localIndex != UNKNOWN_LOCAL_INDEX && gNetworkPlayers[localIndex].connected) {
|
||||
name = gNetworkPlayers[localIndex].name;
|
||||
}
|
||||
djui_language_replace(DLANG(NOTIF, PEER_FAILED), built, 256, '@', name);
|
||||
djui_popup_create(built, 2);
|
||||
}
|
||||
break;
|
||||
case MERR_LOBBY_NOT_FOUND:
|
||||
djui_popup_create(DLANG(NOTIF, LOBBY_NOT_FOUND), 2);
|
||||
network_shutdown(false, false, false, false);
|
||||
break;
|
||||
case MERR_LOBBY_JOIN_FULL:
|
||||
djui_popup_create(DLANG(NOTIF, LOBBY_JOIN_FULL), 2);
|
||||
network_shutdown(false, false, false, false);
|
||||
break;
|
||||
case MERR_LOBBY_JOIN_FAILED:
|
||||
djui_popup_create(DLANG(NOTIF, LOBBY_JOIN_FAILED), 2);
|
||||
network_shutdown(false, false, false, false);
|
||||
break;
|
||||
case MERR_LOBBY_PASSWORD_INCORRECT:
|
||||
djui_popup_create(DLANG(NOTIF, LOBBY_PASSWORD_INCORRECT), 2);
|
||||
network_shutdown(false, false, false, false);
|
||||
break;
|
||||
case MERR_NONE:
|
||||
case MERR_MAX:
|
||||
break;
|
||||
}
|
||||
}
|
||||
static bool ns_coopnet_initialize(enum NetworkType networkType, bool reconnecting) {
|
||||
sNetworkType = networkType;
|
||||
sReconnecting = reconnecting;
|
||||
if (reconnecting) { return true; }
|
||||
return coopnet_is_connected()
|
||||
? true
|
||||
: (coopnet_initialize() == COOPNET_OK);
|
||||
}
|
||||
|
||||
static char* ns_coopnet_get_id_str(u8 localIndex) {
|
||||
static char id_str[32] = { 0 };
|
||||
if (localIndex == UNKNOWN_LOCAL_INDEX) {
|
||||
snprintf(id_str, 32, "???");
|
||||
} else {
|
||||
uint64_t userId = ns_coopnet_get_id(localIndex);
|
||||
uint64_t destId = coopnet_get_dest_id(userId);
|
||||
snprintf(id_str, 32, "%" PRIu64 "", destId);
|
||||
}
|
||||
return id_str;
|
||||
}
|
||||
|
||||
static bool ns_coopnet_match_addr(void* addr1, void* addr2) {
|
||||
return !memcmp(addr1, addr2, sizeof(u64));
|
||||
}
|
||||
|
||||
bool ns_coopnet_is_connected(void) {
|
||||
return coopnet_is_connected();
|
||||
}
|
||||
|
||||
static void coopnet_populate_description(void) {
|
||||
char* buffer = sCoopNetDescription;
|
||||
int bufferLength = 256;
|
||||
// get version
|
||||
char* version = get_version();
|
||||
int versionLength = strlen(version);
|
||||
snprintf(buffer, bufferLength, "%s", version);
|
||||
buffer += versionLength;
|
||||
bufferLength -= versionLength;
|
||||
|
||||
// get mod strings
|
||||
if (gActiveMods.entryCount <= 0) { return; }
|
||||
char* strings[gActiveMods.entryCount];
|
||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||
strings[i] = gActiveMods.entries[i]->name;
|
||||
}
|
||||
|
||||
// add seperator
|
||||
char* sep = "\n\nMods:\n";
|
||||
snprintf(buffer, bufferLength, "%s", sep);
|
||||
buffer += strlen(sep);
|
||||
bufferLength -= strlen(sep);
|
||||
|
||||
// concat mod strings
|
||||
str_seperator_concat(buffer, bufferLength, strings, gActiveMods.entryCount, "\n");
|
||||
}
|
||||
|
||||
void ns_coopnet_update(void) {
|
||||
if (!coopnet_is_connected()) { return; }
|
||||
|
||||
coopnet_update();
|
||||
if (gNetworkType != NT_NONE && sNetworkType != NT_NONE) {
|
||||
if (sNetworkType == NT_SERVER) {
|
||||
char mode[64] = "";
|
||||
mods_get_main_mod_name(mode, 64);
|
||||
if (sReconnecting) {
|
||||
LOG_INFO("Update lobby");
|
||||
coopnet_populate_description();
|
||||
coopnet_lobby_update(sLocalLobbyId, CN_GAME_STR, get_version(), configPlayerName, mode, sCoopNetDescription);
|
||||
} else {
|
||||
LOG_INFO("Create lobby");
|
||||
snprintf(gCoopNetPassword, 64, "%s", configPassword);
|
||||
coopnet_populate_description();
|
||||
coopnet_lobby_create(CN_GAME_STR, get_version(), configPlayerName, mode, (uint16_t)configAmountofPlayers, gCoopNetPassword, sCoopNetDescription);
|
||||
}
|
||||
} else if (sNetworkType == NT_CLIENT) {
|
||||
LOG_INFO("Join lobby");
|
||||
coopnet_lobby_join(gCoopNetDesiredLobby, gCoopNetPassword);
|
||||
}
|
||||
sNetworkType = NT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int ns_coopnet_network_send(u8 localIndex, void* address, u8* data, u16 dataLength) {
|
||||
if (!coopnet_is_connected()) { return 1; }
|
||||
//if (gCurLobbyId == 0) { return 2; }
|
||||
u64 userId = coopnet_raw_get_id(localIndex);
|
||||
if (localIndex == 0 && address != NULL) { userId = *(u64*)address; }
|
||||
coopnet_send_to(userId, data, dataLength);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool coopnet_allow_invite(void) {
|
||||
if (sLocalLobbyId == 0) { return false; }
|
||||
return (sLocalLobbyOwnerId == coopnet_get_local_user_id()) || (strlen(gCoopNetPassword) == 0);
|
||||
}
|
||||
|
||||
static void ns_coopnet_get_lobby_id(UNUSED char* destination, UNUSED u32 destLength) {
|
||||
if (sLocalLobbyId == 0) {
|
||||
snprintf(destination, destLength, "%s", "");
|
||||
} else {
|
||||
snprintf(destination, destLength, "coopnet:%" PRIu64 "", sLocalLobbyId);
|
||||
}
|
||||
}
|
||||
|
||||
static void ns_coopnet_get_lobby_secret(UNUSED char* destination, UNUSED u32 destLength) {
|
||||
if (sLocalLobbyId == 0 || !coopnet_allow_invite()) {
|
||||
snprintf(destination, destLength, "%s", "");
|
||||
} else {
|
||||
snprintf(destination, destLength, "coopnet:%" PRIu64":%s", sLocalLobbyId, gCoopNetPassword);
|
||||
}
|
||||
}
|
||||
|
||||
static void ns_coopnet_shutdown(bool reconnecting) {
|
||||
if (reconnecting) { return; }
|
||||
LOG_INFO("Coopnet shutdown!");
|
||||
coopnet_shutdown();
|
||||
gCoopNetCallbacks.OnLobbyListGot = NULL;
|
||||
gCoopNetCallbacks.OnLobbyListFinish = NULL;
|
||||
|
||||
sLocalLobbyId = 0;
|
||||
sLocalLobbyOwnerId = 0;
|
||||
}
|
||||
|
||||
static CoopNetRc coopnet_initialize(void) {
|
||||
gCoopNetCallbacks.OnConnected = coopnet_on_connected;
|
||||
gCoopNetCallbacks.OnDisconnected = coopnet_on_disconnected;
|
||||
gCoopNetCallbacks.OnReceive = coopnet_on_receive;
|
||||
gCoopNetCallbacks.OnLobbyJoined = coopnet_on_lobby_joined;
|
||||
gCoopNetCallbacks.OnLobbyLeft = coopnet_on_lobby_left;
|
||||
gCoopNetCallbacks.OnError = coopnet_on_error;
|
||||
gCoopNetCallbacks.OnPeerDisconnected = coopnet_on_peer_disconnected;
|
||||
|
||||
if (coopnet_is_connected()) { return COOPNET_OK; }
|
||||
|
||||
CoopNetRc rc = coopnet_begin(configCoopNetIp, configCoopNetPort);
|
||||
if (rc == COOPNET_FAILED) {
|
||||
djui_popup_create(DLANG(NOTIF, COOPNET_CONNECTION_FAILED), 2);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct NetworkSystem gNetworkSystemCoopNet = {
|
||||
.initialize = ns_coopnet_initialize,
|
||||
.get_id = ns_coopnet_get_id,
|
||||
.get_id_str = ns_coopnet_get_id_str,
|
||||
.save_id = ns_coopnet_save_id,
|
||||
.clear_id = ns_coopnet_clear_id,
|
||||
.dup_addr = ns_coopnet_dup_addr,
|
||||
.match_addr = ns_coopnet_match_addr,
|
||||
.update = ns_coopnet_update,
|
||||
.send = ns_coopnet_network_send,
|
||||
.get_lobby_id = ns_coopnet_get_lobby_id,
|
||||
.get_lobby_secret = ns_coopnet_get_lobby_secret,
|
||||
.shutdown = ns_coopnet_shutdown,
|
||||
.requireServerBroadcast = false,
|
||||
.name = "CoopNet",
|
||||
};
|
||||
|
||||
#endif
|
17
src/pc/network/coopnet/coopnet.h
Normal file
17
src/pc/network/coopnet/coopnet.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef COOPNET_H
|
||||
#define COOPNET_H
|
||||
#ifdef COOPNET
|
||||
|
||||
typedef void (*QueryCallbackPtr)(uint64_t aLobbyId, uint64_t aOwnerId, uint16_t aConnections, uint16_t aMaxConnections, const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, const char* aDescription);
|
||||
typedef void (*QueryFinishCallbackPtr)(void);
|
||||
|
||||
extern struct NetworkSystem gNetworkSystemCoopNet;
|
||||
extern uint64_t gCoopNetDesiredLobby;
|
||||
extern char gCoopNetPassword[];
|
||||
|
||||
bool ns_coopnet_query(QueryCallbackPtr callback, QueryFinishCallbackPtr finishCallback, const char* password);
|
||||
bool ns_coopnet_is_connected(void);
|
||||
void ns_coopnet_update(void);
|
||||
|
||||
#endif
|
||||
#endif
|
103
src/pc/network/coopnet/coopnet_id.c
Normal file
103
src/pc/network/coopnet/coopnet_id.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "libcoopnet.h"
|
||||
#include "coopnet.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
static uint64_t sLocalUserId = 0;
|
||||
static uint64_t sNetworkUserIds[MAX_PLAYERS] = { 0 };
|
||||
|
||||
#define MAX_DEST_IDS (MAX_PLAYERS * 2)
|
||||
struct DestinationId {
|
||||
uint64_t userId;
|
||||
uint64_t destId;
|
||||
};
|
||||
struct DestinationId sDestinationIds[MAX_DEST_IDS] = { 0 };
|
||||
|
||||
void coopnet_save_dest_id(uint64_t userId, uint64_t destId) {
|
||||
struct DestinationId* dest = NULL;
|
||||
for (int i = 0; i < MAX_DEST_IDS; i++) {
|
||||
if (sDestinationIds[i].userId == userId) {
|
||||
sDestinationIds[i].destId = destId;
|
||||
return;
|
||||
} else if (dest == NULL && sDestinationIds[i].userId == 0) {
|
||||
dest = &sDestinationIds[i];
|
||||
}
|
||||
}
|
||||
if (dest) {
|
||||
dest->userId = userId;
|
||||
dest->destId = destId;
|
||||
}
|
||||
}
|
||||
|
||||
void coopnet_clear_dest_id(uint64_t userId) {
|
||||
for (int i = 0; i < MAX_DEST_IDS; i++) {
|
||||
if (sDestinationIds[i].userId == userId) {
|
||||
sDestinationIds[i].userId = 0;
|
||||
sDestinationIds[i].destId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void coopnet_clear_dest_ids(void) {
|
||||
for (int i = 0; i < MAX_DEST_IDS; i++) {
|
||||
sDestinationIds[i].userId = 0;
|
||||
sDestinationIds[i].destId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t coopnet_get_dest_id(uint64_t userId) {
|
||||
for (int i = 0; i < MAX_DEST_IDS; i++) {
|
||||
if (sDestinationIds[i].userId == userId) {
|
||||
return sDestinationIds[i].destId;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 coopnet_user_id_to_local_index(uint64_t userId) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (gNetworkPlayers[i].connected && sNetworkUserIds[i] == userId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return UNKNOWN_LOCAL_INDEX;
|
||||
}
|
||||
|
||||
void coopnet_set_user_id(uint8_t localIndex, uint64_t userId) {
|
||||
sNetworkUserIds[localIndex] = userId;
|
||||
}
|
||||
|
||||
uint64_t coopnet_get_local_user_id(void) {
|
||||
return sLocalUserId;
|
||||
}
|
||||
|
||||
void coopnet_set_local_user_id(uint64_t userId) {
|
||||
sLocalUserId = userId;
|
||||
}
|
||||
|
||||
s64 coopnet_raw_get_id(u8 localIndex) {
|
||||
return (s64)sNetworkUserIds[localIndex];
|
||||
}
|
||||
|
||||
s64 ns_coopnet_get_id(u8 localIndex) {
|
||||
if (localIndex == 0) { return (s64)sLocalUserId; }
|
||||
return (s64)sNetworkUserIds[localIndex];
|
||||
}
|
||||
|
||||
void ns_coopnet_save_id(u8 localIndex, s64 networkId) {
|
||||
SOFT_ASSERT(localIndex > 0);
|
||||
SOFT_ASSERT(localIndex < MAX_PLAYERS);
|
||||
sNetworkUserIds[localIndex] = (networkId == 0) ? sNetworkUserIds[0] : (u64)networkId;
|
||||
}
|
||||
|
||||
void ns_coopnet_clear_id(u8 localIndex) {
|
||||
if (localIndex == 0) { return; }
|
||||
SOFT_ASSERT(localIndex < MAX_PLAYERS);
|
||||
sNetworkUserIds[localIndex] = 0;
|
||||
}
|
||||
|
||||
void* ns_coopnet_dup_addr(u8 localIndex) {
|
||||
void* address = malloc(sizeof(u64));
|
||||
memcpy(address, &sNetworkUserIds[localIndex], sizeof(u64));
|
||||
return address;
|
||||
}
|
19
src/pc/network/coopnet/coopnet_id.h
Normal file
19
src/pc/network/coopnet/coopnet_id.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "PR/ultratypes.h"
|
||||
|
||||
void coopnet_save_dest_id(uint64_t userId, uint64_t destId);
|
||||
void coopnet_clear_dest_id(uint64_t userId);
|
||||
void coopnet_clear_dest_ids(void);
|
||||
uint64_t coopnet_get_dest_id(uint64_t userId);
|
||||
|
||||
u8 coopnet_user_id_to_local_index(uint64_t userId);
|
||||
void coopnet_set_user_id(uint8_t localIndex, uint64_t userId);
|
||||
uint64_t coopnet_get_local_user_id(void);
|
||||
void coopnet_set_local_user_id(uint64_t userId);
|
||||
|
||||
s64 coopnet_raw_get_id(u8 localIndex);
|
||||
s64 ns_coopnet_get_id(u8 localIndex);
|
||||
void ns_coopnet_save_id(u8 localIndex, s64 networkId);
|
||||
void ns_coopnet_clear_id(u8 localIndex);
|
||||
void* ns_coopnet_dup_addr(u8 localIndex);
|
|
@ -1,171 +0,0 @@
|
|||
#include "activity.h"
|
||||
#include "lobby.h"
|
||||
#include "discord_network.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/network/version.h"
|
||||
#include "pc/djui/djui.h"
|
||||
#include "pc/mods/mods.h"
|
||||
#include "pc/logfile.h"
|
||||
|
||||
#define HASH_LENGTH 8
|
||||
struct DiscordActivity gCurActivity = { 0 };
|
||||
bool gActivityLock = false;
|
||||
|
||||
static void on_activity_update_callback(UNUSED void* data, enum EDiscordResult result) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_activity_update_callback returned %d", result);
|
||||
DISCORD_REQUIRE(result);
|
||||
}
|
||||
|
||||
static void on_activity_join_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordLobby* lobby) {
|
||||
gActivityLock = false;
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join_callback returned %d, lobby " DISCORD_ID_FORMAT ", owner " DISCORD_ID_FORMAT, result, lobby->id, lobby->owner_id);
|
||||
DISCORD_REQUIRE(result);
|
||||
if (gNetworkType != NT_NONE) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "Joined lobby when already connected somewhere!");
|
||||
return;
|
||||
}
|
||||
network_reset_reconnect_and_rehost();
|
||||
network_init(NT_CLIENT);
|
||||
|
||||
gCurActivity.type = DiscordActivityType_Playing;
|
||||
if (snprintf(gCurActivity.party.id, 128, DISCORD_ID_FORMAT, lobby->id) < 0) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "Truncating party id");
|
||||
}
|
||||
gCurActivity.party.size.current_size = 2;
|
||||
gCurActivity.party.size.max_size = lobby->capacity;
|
||||
|
||||
gCurLobbyId = lobby->id;
|
||||
|
||||
discord_network_init(lobby->id);
|
||||
discord_activity_update(false);
|
||||
|
||||
if (gNetworkPlayerServer == NULL) {
|
||||
network_player_connected(NPT_SERVER, 0, 0, &DEFAULT_MARIO_PALETTE, "Player");
|
||||
}
|
||||
ns_discord_save_id(gNetworkPlayerServer->localIndex, lobby->owner_id);
|
||||
network_send_mod_list_request();
|
||||
|
||||
gNetworkUserIds[0] = lobby->owner_id;
|
||||
}
|
||||
|
||||
static void on_activity_join(UNUSED void* data, const char* secret) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join, secret: %s", secret);
|
||||
if (gActivityLock) { return; }
|
||||
gActivityLock = true;
|
||||
djui_connect_menu_open();
|
||||
app.lobbies->connect_lobby_with_activity_secret(app.lobbies, (char*)secret, NULL, on_activity_join_callback);
|
||||
}
|
||||
|
||||
static void on_activity_join_request_callback(UNUSED void* data, enum EDiscordResult result) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join_request_callback returned %d", (int)result);
|
||||
DISCORD_REQUIRE(result);
|
||||
}
|
||||
|
||||
static void on_activity_join_request(UNUSED void* data, struct DiscordUser* user) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join_request from " DISCORD_ID_FORMAT, user->id);
|
||||
//app.activities->send_request_reply(app.activities, user->id, DiscordActivityJoinRequestReply_Yes, NULL, on_activity_join_request_callback);
|
||||
}
|
||||
|
||||
static void strncat_len(char* destination, char* source, size_t destinationLength, size_t sourceLength) {
|
||||
char altered[128] = { 0 };
|
||||
snprintf(altered, (sourceLength < 127) ? sourceLength : 127, "%s", source);
|
||||
strncat(destination, altered, destinationLength);
|
||||
}
|
||||
|
||||
static bool discord_populate_details(char* details, bool shorten) {
|
||||
snprintf(details, 127, "%s", get_version());
|
||||
|
||||
bool displayDash = true;
|
||||
bool displayComma = false;
|
||||
size_t catLength = shorten ? 14 : 64;
|
||||
|
||||
if (gRegisteredMods.string != NULL) {
|
||||
strncat_len(details, " - ", 127, catLength);
|
||||
displayDash = false;
|
||||
|
||||
// add patches to activity
|
||||
struct StringLinkedList* node = &gRegisteredMods;
|
||||
while (node != NULL && node->string != NULL) {
|
||||
if (displayComma) { strncat_len(details, ", ", 127, catLength); }
|
||||
strncat_len(details, node->string, 127, catLength);
|
||||
displayComma = true;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (gActiveMods.entryCount > 0) {
|
||||
// add mods to activity
|
||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||
struct Mod* mod = gActiveMods.entries[i];
|
||||
if (displayDash) { strncat_len(details, " - ", 127, catLength); }
|
||||
if (displayComma) { strncat_len(details, ", ", 127, catLength); }
|
||||
|
||||
strncat_len(details, mod->name, 127, catLength);
|
||||
|
||||
displayDash = false;
|
||||
displayComma = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (strlen(details) >= 125);
|
||||
}
|
||||
|
||||
void discord_activity_update(bool hosting) {
|
||||
gCurActivity.type = DiscordActivityType_Playing;
|
||||
if (gCurActivity.party.size.current_size > 1) {
|
||||
strcpy(gCurActivity.state, "Playing!");
|
||||
} else if (hosting) {
|
||||
strcpy(gCurActivity.state, "Waiting for players...");
|
||||
} else {
|
||||
strcpy(gCurActivity.state, "In-game.");
|
||||
gCurActivity.party.size.current_size = 1;
|
||||
if (gCurActivity.party.size.max_size < 1) { gCurActivity.party.size.max_size = 1; }
|
||||
}
|
||||
|
||||
char details[256] = { 0 };
|
||||
bool overrun = discord_populate_details(details, false);
|
||||
if (overrun) {
|
||||
discord_populate_details(details, true);
|
||||
}
|
||||
|
||||
if (snprintf(gCurActivity.details, 125, "%s", details) < 0) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "truncating details");
|
||||
}
|
||||
|
||||
if (!app.activities) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "no activities");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!app.activities->update_activity) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "no update_activity");
|
||||
return;
|
||||
}
|
||||
|
||||
app.activities->update_activity(app.activities, &gCurActivity, NULL, on_activity_update_callback);
|
||||
LOGFILE_INFO(LFT_DISCORD, "set activity");
|
||||
}
|
||||
|
||||
void discord_activity_update_check(void) {
|
||||
if (gNetworkType == NT_NONE) { return; }
|
||||
bool shouldUpdate = false;
|
||||
u8 connectedCount = network_player_connected_count();
|
||||
|
||||
if (connectedCount > 0) {
|
||||
if (connectedCount != gCurActivity.party.size.current_size) {
|
||||
gCurActivity.party.size.current_size = connectedCount;
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
discord_activity_update(gNetworkType == NT_SERVER);
|
||||
}
|
||||
}
|
||||
|
||||
struct IDiscordActivityEvents* discord_activity_initialize(void) {
|
||||
static struct IDiscordActivityEvents events = { 0 };
|
||||
events.on_activity_join = on_activity_join;
|
||||
events.on_activity_join_request = on_activity_join_request;
|
||||
return &events;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef DISCORD_ACTIVITY_H
|
||||
#define DISCORD_ACTIVITY_H
|
||||
#include "discord.h"
|
||||
|
||||
extern struct DiscordActivity gCurActivity;
|
||||
|
||||
void discord_activity_update(bool hosting);
|
||||
void discord_activity_update_check(void);
|
||||
struct IDiscordActivityEvents* discord_activity_initialize(void);
|
||||
extern bool gActivityLock;
|
||||
|
||||
#endif
|
|
@ -1,203 +0,0 @@
|
|||
#include "discord.h"
|
||||
#include "user.h"
|
||||
#include "activity.h"
|
||||
#include "lobby.h"
|
||||
#include "discord_network.h"
|
||||
#include "pc/network/version.h"
|
||||
#include "pc/djui/djui.h"
|
||||
#include "pc/logfile.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#include <winuser.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
|
||||
#define MAX_LAUNCH_CMD (MAX_PATH + 12)
|
||||
|
||||
static int64_t applicationId = 752700005210390568;
|
||||
struct DiscordApplication app = { 0 };
|
||||
bool gDiscordInitialized = false;
|
||||
bool gDiscordFailed = false;
|
||||
bool alreadyRun = false;
|
||||
|
||||
static void discord_sdk_log_callback(UNUSED void* hook_data, enum EDiscordLogLevel level, const char* message) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "callback (%d): %s", level, message);
|
||||
}
|
||||
|
||||
void discord_fatal_message(int rc) { // Discord usually does this because of loss of connection to Discord
|
||||
char errorMessage[132] = { 0 };
|
||||
snprintf(errorMessage, 132, "%s\nRC: %d", DLANG(NOTIF, DISCORD_ERROR), rc);
|
||||
djui_popup_create(errorMessage, 6);
|
||||
}
|
||||
|
||||
void discord_fatal(int rc) {
|
||||
if (!alreadyRun) {
|
||||
discord_fatal_message(rc);
|
||||
alreadyRun = true;
|
||||
}
|
||||
|
||||
if (rc != DiscordResult_Ok) {
|
||||
LOG_ERROR("Discord threw an error. RC: %d", rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_instance_env_variable(void) {
|
||||
// set local instance id
|
||||
char environmentVariables[128] = { 0 };
|
||||
int instance = (gCLIOpts.Discord == 0) ? 0 : (gCLIOpts.Discord - 1);
|
||||
snprintf(environmentVariables, 128, "DISCORD_INSTANCE_ID=%d", instance);
|
||||
putenv(environmentVariables);
|
||||
LOGFILE_INFO(LFT_DISCORD, "set environment variables: %s", environmentVariables);
|
||||
}
|
||||
|
||||
static void get_oauth2_token_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordOAuth2Token* token) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> get_oauth2_token_callback returned %d", result);
|
||||
if (result != DiscordResult_Ok) { return; }
|
||||
LOGFILE_INFO(LFT_DISCORD, "OAuth2 token: %s", token->access_token);
|
||||
}
|
||||
|
||||
static void register_launch_command(void) {
|
||||
char cmd[MAX_LAUNCH_CMD] = { 0 };
|
||||
int rc;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HMODULE hModule = GetModuleHandle(NULL);
|
||||
if (hModule == NULL) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "unable to retrieve absolute path!");
|
||||
return;
|
||||
}
|
||||
GetModuleFileName(hModule, cmd, sizeof(cmd));
|
||||
#else
|
||||
char path[MAX_LAUNCH_CMD] = { 0 };
|
||||
snprintf(path, MAX_LAUNCH_CMD - 1, "/proc/%d/exe", getpid());
|
||||
rc = readlink(path, cmd, MAX_LAUNCH_CMD - 1);
|
||||
if (rc <= 0) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "unable to retrieve absolute path! rc = %d", rc);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
strncat(cmd, " --discord 1", MAX_LAUNCH_CMD - 1);
|
||||
rc = app.activities->register_command(app.activities, cmd);
|
||||
if (rc != DiscordResult_Ok) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "register command failed %d", rc);
|
||||
return;
|
||||
}
|
||||
LOGFILE_INFO(LFT_DISCORD, "cmd: %s", cmd);
|
||||
}
|
||||
|
||||
static void* ns_discord_dup_addr(u8 localIndex) {
|
||||
void* address = malloc(sizeof(DiscordUserId));
|
||||
memcpy(address, &gNetworkUserIds[localIndex], sizeof(DiscordUserId));
|
||||
return address;
|
||||
}
|
||||
|
||||
static bool ns_discord_match_addr(void* addr1, void* addr2) {
|
||||
return !memcmp(addr1, addr2, sizeof(u64));
|
||||
}
|
||||
|
||||
static void ns_discord_update(void) {
|
||||
if (!gDiscordInitialized) { return; }
|
||||
|
||||
discord_activity_update_check();
|
||||
discord_lobby_update();
|
||||
DISCORD_REQUIRE(app.core->run_callbacks(app.core));
|
||||
discord_network_flush();
|
||||
}
|
||||
|
||||
static bool ns_discord_initialize(enum NetworkType networkType) {
|
||||
if (gDiscordReconnecting) { return true; }
|
||||
#ifdef DEBUG
|
||||
set_instance_env_variable();
|
||||
#endif
|
||||
|
||||
if (app.core != NULL) {
|
||||
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
|
||||
}
|
||||
|
||||
if (!gDiscordInitialized) {
|
||||
// set up discord params
|
||||
struct DiscordCreateParams params = { 0 };
|
||||
DiscordCreateParamsSetDefault(¶ms);
|
||||
params.client_id = applicationId;
|
||||
params.flags = DiscordCreateFlags_NoRequireDiscord;
|
||||
params.event_data = &app;
|
||||
params.user_events = discord_user_initialize();
|
||||
params.activity_events = discord_activity_initialize();
|
||||
params.lobby_events = discord_lobby_initialize();
|
||||
|
||||
gCurLobbyId = 0;
|
||||
gLobbyCreateRetry = false;
|
||||
gLobbyCreateAttempts = 0;
|
||||
gLobbyCreateAttemptElapsed = 0;
|
||||
|
||||
int rc = DiscordCreate(DISCORD_VERSION, ¶ms, &app.core);
|
||||
if (app.core != NULL) {
|
||||
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
|
||||
}
|
||||
gDiscordFailed = false;
|
||||
if (networkType != NT_NONE) {
|
||||
DISCORD_REQUIRE(rc);
|
||||
} else if (rc) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "DiscordCreate failed: %d", rc);
|
||||
djui_popup_create(DLANG(NOTIF, DISCORD_DETECT), 3);
|
||||
gDiscordFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// set up manager pointers
|
||||
if (app.core != NULL) {
|
||||
app.users = app.core->get_user_manager(app.core);
|
||||
app.achievements = app.core->get_achievement_manager(app.core);
|
||||
app.activities = app.core->get_activity_manager(app.core);
|
||||
app.application = app.core->get_application_manager(app.core);
|
||||
app.lobbies = app.core->get_lobby_manager(app.core);
|
||||
}
|
||||
|
||||
// register launch params
|
||||
register_launch_command();
|
||||
|
||||
// get oath2 token
|
||||
app.application->get_oauth2_token(app.application, NULL, get_oauth2_token_callback);
|
||||
|
||||
// set activity
|
||||
discord_activity_update(false);
|
||||
}
|
||||
|
||||
// create lobby
|
||||
if (networkType == NT_SERVER) {
|
||||
discord_lobby_create();
|
||||
gActivityLock = true;
|
||||
} else {
|
||||
gActivityLock = false;
|
||||
}
|
||||
|
||||
gDiscordInitialized = true;
|
||||
LOGFILE_INFO(LFT_DISCORD, "initialized");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ns_discord_shutdown(void) {
|
||||
if (gDiscordReconnecting) { return; }
|
||||
if (!gDiscordInitialized) { return; }
|
||||
discord_lobby_leave();
|
||||
gActivityLock = false;
|
||||
LOGFILE_INFO(LFT_DISCORD, "shutdown");
|
||||
}
|
||||
|
||||
struct NetworkSystem gNetworkSystemDiscord = {
|
||||
.initialize = ns_discord_initialize,
|
||||
.get_id = ns_discord_get_id,
|
||||
.get_id_str = ns_discord_get_id_str,
|
||||
.save_id = ns_discord_save_id,
|
||||
.clear_id = ns_discord_clear_id,
|
||||
.dup_addr = ns_discord_dup_addr,
|
||||
.match_addr = ns_discord_match_addr,
|
||||
.update = ns_discord_update,
|
||||
.send = ns_discord_network_send,
|
||||
.shutdown = ns_discord_shutdown,
|
||||
.requireServerBroadcast = false,
|
||||
.name = "Discord",
|
||||
};
|
|
@ -1,84 +0,0 @@
|
|||
#include "discord_network.h"
|
||||
#include "lobby.h"
|
||||
#include "pc/logfile.h"
|
||||
|
||||
int64_t gNetworkUserIds[MAX_PLAYERS] = { 0 };
|
||||
|
||||
u8 discord_user_id_to_local_index(int64_t userId) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (gNetworkPlayers[i].connected && gNetworkUserIds[i] == userId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return UNKNOWN_LOCAL_INDEX;
|
||||
}
|
||||
|
||||
int ns_discord_network_send(u8 localIndex, void* address, u8* data, u16 dataLength) {
|
||||
if (!gDiscordInitialized) { return 1; }
|
||||
if (gCurLobbyId == 0) { return 2; }
|
||||
DiscordUserId userId = gNetworkUserIds[localIndex];
|
||||
if (localIndex == 0 && address != NULL) { userId = *(DiscordUserId*)address; }
|
||||
DISCORD_REQUIRE(app.lobbies->send_network_message(app.lobbies, gCurLobbyId, userId, 0, data, dataLength));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void discord_network_on_message(UNUSED void* eventData, UNUSED int64_t lobbyId, int64_t userId, UNUSED uint8_t channelId, uint8_t* data, uint32_t dataLength) {
|
||||
gNetworkUserIds[0] = userId;
|
||||
|
||||
u8 localIndex = UNKNOWN_LOCAL_INDEX;
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (gNetworkUserIds[i] == userId) {
|
||||
localIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
network_receive(localIndex, &userId, (u8*)data, (u16)dataLength);
|
||||
}
|
||||
|
||||
void discord_network_flush(void) {
|
||||
app.lobbies->flush_network(app.lobbies);
|
||||
}
|
||||
|
||||
s64 ns_discord_get_id(u8 localId) {
|
||||
if (localId == 0) { return app.userId; }
|
||||
return gNetworkUserIds[localId];
|
||||
}
|
||||
|
||||
char* ns_discord_get_id_str(u8 localId) {
|
||||
static char id_str[22] = { 0 };
|
||||
if (localId == UNKNOWN_LOCAL_INDEX) {
|
||||
snprintf(id_str, 22, "???");
|
||||
} else {
|
||||
snprintf(id_str, 22, "%lld", (long long int)ns_discord_get_id(localId));
|
||||
}
|
||||
return id_str;
|
||||
}
|
||||
|
||||
void ns_discord_save_id(u8 localId, s64 networkId) {
|
||||
SOFT_ASSERT(localId > 0);
|
||||
SOFT_ASSERT(localId < MAX_PLAYERS);
|
||||
gNetworkUserIds[localId] = (networkId == 0) ? gNetworkUserIds[0] : networkId;
|
||||
LOGFILE_INFO(LFT_DISCORD, "saved user id %d == " DISCORD_ID_FORMAT, localId, gNetworkUserIds[localId]);
|
||||
}
|
||||
|
||||
void ns_discord_clear_id(u8 localId) {
|
||||
if (localId == 0) { return; }
|
||||
SOFT_ASSERT(localId < MAX_PLAYERS);
|
||||
gNetworkUserIds[localId] = 0;
|
||||
LOGFILE_INFO(LFT_DISCORD, "cleared user id %d == " DISCORD_ID_FORMAT, localId, gNetworkUserIds[localId]);
|
||||
}
|
||||
|
||||
void discord_network_init(int64_t lobbyId) {
|
||||
DISCORD_REQUIRE(app.lobbies->connect_network(app.lobbies, lobbyId));
|
||||
DISCORD_REQUIRE(app.lobbies->open_network_channel(app.lobbies, lobbyId, 0, false));
|
||||
LOGFILE_INFO(LFT_DISCORD, "network initialized");
|
||||
}
|
||||
|
||||
void discord_network_shutdown(void) {
|
||||
if (gCurLobbyId == 0) { return; }
|
||||
app.lobbies->flush_network(app.lobbies);
|
||||
app.lobbies->disconnect_network(app.lobbies, gCurLobbyId);
|
||||
app.lobbies->flush_network(app.lobbies);
|
||||
LOGFILE_INFO(LFT_DISCORD, "shutdown network, lobby = " DISCORD_ID_FORMAT, gCurLobbyId);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef DISCORD_NETWORK_H
|
||||
#define DISCORD_NETWORK_H
|
||||
#include "discord.h"
|
||||
|
||||
extern int64_t gNetworkUserIds[MAX_PLAYERS];
|
||||
|
||||
u8 discord_user_id_to_local_index(int64_t userId);
|
||||
int ns_discord_network_send(u8 localIndex, void* addr, u8* data, u16 dataLength);
|
||||
void discord_network_on_message(UNUSED void* eventData, int64_t lobbyId, int64_t userId, uint8_t channelId, uint8_t* data, uint32_t dataLength);
|
||||
void discord_network_flush(void);
|
||||
s64 ns_discord_get_id(u8 localId);
|
||||
char* ns_discord_get_id_str(u8 localId);
|
||||
void ns_discord_save_id(u8 localId, s64 networkId);
|
||||
void ns_discord_clear_id(u8 localId);
|
||||
void discord_network_init(int64_t lobbyId);
|
||||
void discord_network_shutdown(void);
|
||||
|
||||
#endif
|
|
@ -1,137 +0,0 @@
|
|||
#include "lobby.h"
|
||||
#include "activity.h"
|
||||
#include "discord_network.h"
|
||||
#include "pc/logfile.h"
|
||||
#include "pc/utils/misc.h"
|
||||
#include "pc/configfile.h"
|
||||
|
||||
#define MAX_LOBBY_RETRY 5
|
||||
#define MAX_LOBBY_RETRY_WAIT_TIME 6
|
||||
|
||||
static bool isHosting = false;
|
||||
DiscordLobbyId gCurLobbyId = 0;
|
||||
|
||||
bool gLobbyCreateRetry = false;
|
||||
u8 gLobbyCreateAttempts = 0;
|
||||
f32 gLobbyCreateAttemptElapsed = 0;
|
||||
|
||||
void discord_lobby_update(void) {
|
||||
if (gCurLobbyId != 0) { return; }
|
||||
if (!gLobbyCreateRetry) { return; }
|
||||
f32 timeUntilRetry = (clock_elapsed() - gLobbyCreateAttemptElapsed);
|
||||
if (timeUntilRetry < MAX_LOBBY_RETRY_WAIT_TIME) { return; }
|
||||
gLobbyCreateRetry = false;
|
||||
discord_lobby_create();
|
||||
}
|
||||
|
||||
static void on_lobby_create_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordLobby* lobby) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_lobby_create returned %d", (int)result);
|
||||
|
||||
if (result != DiscordResult_Ok && gLobbyCreateAttempts < MAX_LOBBY_RETRY) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "rescheduling lobby creation");
|
||||
gLobbyCreateRetry = true;
|
||||
gLobbyCreateAttempts++;
|
||||
gLobbyCreateAttemptElapsed = clock_elapsed();
|
||||
return;
|
||||
}
|
||||
|
||||
DISCORD_REQUIRE(result);
|
||||
LOGFILE_INFO(LFT_DISCORD, "Lobby id: " DISCORD_ID_FORMAT, lobby->id);
|
||||
LOGFILE_INFO(LFT_DISCORD, "Lobby type: %u", lobby->type);
|
||||
LOGFILE_INFO(LFT_DISCORD, "Lobby owner id: " DISCORD_ID_FORMAT, lobby->owner_id);
|
||||
LOGFILE_INFO(LFT_DISCORD, "Lobby secret: %s", lobby->secret);
|
||||
LOGFILE_INFO(LFT_DISCORD, "Lobby capacity: %u", lobby->capacity);
|
||||
LOGFILE_INFO(LFT_DISCORD, "Lobby locked: %d", lobby->locked);
|
||||
|
||||
gCurActivity.type = DiscordActivityType_Playing;
|
||||
if (snprintf(gCurActivity.party.id, 128, DISCORD_ID_FORMAT, lobby->id) < 0) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "truncating party id");
|
||||
}
|
||||
gCurActivity.party.size.current_size = 1;
|
||||
gCurActivity.party.size.max_size = configAmountofPlayers;
|
||||
|
||||
char secretJoin[128] = "";
|
||||
if (snprintf(secretJoin, 128, DISCORD_ID_FORMAT ":%s", lobby->id, lobby->secret) < 0) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "truncating secret");
|
||||
}
|
||||
strcpy(gCurActivity.secrets.join, secretJoin);
|
||||
|
||||
isHosting = true;
|
||||
gCurLobbyId = lobby->id;
|
||||
|
||||
discord_network_init(lobby->id);
|
||||
discord_activity_update(true);
|
||||
}
|
||||
|
||||
static void on_lobby_update(UNUSED void* data, int64_t lobbyId) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_lobby_update id: " DISCORD_ID_FORMAT, lobbyId);
|
||||
}
|
||||
|
||||
static void on_member_connect(UNUSED void* data, int64_t lobbyId, int64_t userId) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_member_connect lobby: " DISCORD_ID_FORMAT ", user: " DISCORD_ID_FORMAT, lobbyId, userId);
|
||||
gCurActivity.party.size.current_size++;
|
||||
discord_activity_update(true);
|
||||
}
|
||||
|
||||
static void on_member_update(UNUSED void* data, int64_t lobbyId, int64_t userId) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_member_update lobby: " DISCORD_ID_FORMAT ", user: " DISCORD_ID_FORMAT, lobbyId, userId);
|
||||
}
|
||||
|
||||
static void on_member_disconnect(UNUSED void* data, int64_t lobbyId, int64_t userId) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_member_disconnect lobby: " DISCORD_ID_FORMAT ", user: " DISCORD_ID_FORMAT, lobbyId, userId);
|
||||
u8 localIndex = discord_user_id_to_local_index(userId);
|
||||
if (localIndex != UNKNOWN_LOCAL_INDEX && gNetworkPlayers[localIndex].connected) {
|
||||
network_player_disconnected(gNetworkPlayers[localIndex].globalIndex);
|
||||
}
|
||||
gCurActivity.party.size.current_size--;
|
||||
discord_activity_update(isHosting);
|
||||
}
|
||||
|
||||
void discord_lobby_create(void) {
|
||||
struct IDiscordLobbyTransaction* txn = { 0 };
|
||||
|
||||
DISCORD_REQUIRE(app.lobbies->get_lobby_create_transaction(app.lobbies, &txn));
|
||||
txn->set_capacity(txn, MAX_PLAYERS);
|
||||
txn->set_type(txn, DiscordLobbyType_Public);
|
||||
//txn->set_metadata(txn, "a", "123");
|
||||
|
||||
app.lobbies->create_lobby(app.lobbies, txn, NULL, on_lobby_create_callback);
|
||||
}
|
||||
|
||||
static void on_lobby_leave_callback(UNUSED void* data, enum EDiscordResult result) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_lobby_leave returned %d", result);
|
||||
DISCORD_REQUIRE(result);
|
||||
}
|
||||
|
||||
void discord_lobby_leave(void) {
|
||||
if (gCurLobbyId == 0) { return; }
|
||||
|
||||
discord_network_shutdown();
|
||||
if (isHosting) {
|
||||
app.lobbies->delete_lobby(app.lobbies, gCurLobbyId, NULL, on_lobby_leave_callback);
|
||||
} else {
|
||||
app.lobbies->disconnect_lobby(app.lobbies, gCurLobbyId, NULL, on_lobby_leave_callback);
|
||||
}
|
||||
|
||||
LOGFILE_INFO(LFT_DISCORD, "left lobby " DISCORD_ID_FORMAT, gCurLobbyId);
|
||||
|
||||
if (snprintf(gCurActivity.party.id, 128, "%s", "none") < 0) {
|
||||
LOGFILE_ERROR(LFT_DISCORD, "Truncating party id");
|
||||
}
|
||||
gCurActivity.party.size.current_size = 1;
|
||||
gCurActivity.party.size.max_size = 1;
|
||||
discord_activity_update(gNetworkType == NT_SERVER);
|
||||
|
||||
isHosting = false;
|
||||
gCurLobbyId = 0;
|
||||
}
|
||||
|
||||
struct IDiscordLobbyEvents* discord_lobby_initialize(void) {
|
||||
static struct IDiscordLobbyEvents events = { 0 };
|
||||
events.on_lobby_update = on_lobby_update;
|
||||
events.on_member_connect = on_member_connect;
|
||||
events.on_member_update = on_member_update;
|
||||
events.on_member_disconnect = on_member_disconnect;
|
||||
events.on_network_message = discord_network_on_message;
|
||||
return &events;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef DISCORD_LOBBY_H
|
||||
#define DISCORD_LOBBY_H
|
||||
#include "discord.h"
|
||||
|
||||
extern DiscordLobbyId gCurLobbyId;
|
||||
|
||||
extern bool gLobbyCreateRetry;
|
||||
extern u8 gLobbyCreateAttempts;
|
||||
extern f32 gLobbyCreateAttemptElapsed;
|
||||
|
||||
void discord_lobby_update(void);
|
||||
void discord_lobby_create(void);
|
||||
void discord_lobby_leave(void);
|
||||
struct IDiscordLobbyEvents* discord_lobby_initialize(void);
|
||||
|
||||
#endif
|
|
@ -1,34 +0,0 @@
|
|||
#include "user.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "pc/logfile.h"
|
||||
#include "pc/crash_handler.h"
|
||||
|
||||
static void on_current_user_update(UNUSED void* data) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> on_current_user_update");
|
||||
struct DiscordUser user = { 0 };
|
||||
app.users->get_current_user(app.users, &user);
|
||||
|
||||
// remember user id
|
||||
app.userId = user.id;
|
||||
gPcDebug.id = user.id;
|
||||
|
||||
// copy over discord username if we haven't set one yet
|
||||
if (configPlayerName[0] == '\0' && strlen(user.username) > 0) {
|
||||
char* cname = configPlayerName;
|
||||
char* dname = user.username;
|
||||
for (int i = 0; i < MAX_PLAYER_STRING - 1; i++) {
|
||||
if (*dname >= '!' && *dname <= '~') {
|
||||
*cname = *dname;
|
||||
cname++;
|
||||
}
|
||||
dname++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IDiscordUserEvents* discord_user_initialize(void) {
|
||||
LOGFILE_INFO(LFT_DISCORD, "> discord_user_intitialize");
|
||||
static struct IDiscordUserEvents events = { 0 };
|
||||
events.on_current_user_update = on_current_user_update;
|
||||
return &events;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef DISCORD_USER_H
|
||||
#define DISCORD_USER_H
|
||||
#include "discord.h"
|
||||
|
||||
struct IDiscordUserEvents* discord_user_initialize(void);
|
||||
|
||||
#endif
|
|
@ -1,15 +1,13 @@
|
|||
#include "socket/socket.h"
|
||||
#include "coopnet/coopnet.h"
|
||||
#include <stdio.h>
|
||||
#include "network.h"
|
||||
#include "object_fields.h"
|
||||
#include "game/level_update.h"
|
||||
#include "object_constants.h"
|
||||
#include "behavior_table.h"
|
||||
#include "src/game/hardcoded.h"
|
||||
#include "src/game/scroll_targets.h"
|
||||
#ifdef DISCORD_SDK
|
||||
#include "discord/discord.h"
|
||||
#include "discord/activity.h"
|
||||
#endif
|
||||
#include "pc/configfile.h"
|
||||
#include "pc/cheats.h"
|
||||
#include "pc/djui/djui.h"
|
||||
|
@ -30,6 +28,10 @@
|
|||
#include "game/level_geo.h"
|
||||
#include "menu/intro_geo.h"
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
#include "pc/discord/discord.h"
|
||||
#endif
|
||||
|
||||
// fix warnings when including rendering_graph_node
|
||||
#undef near
|
||||
#undef far
|
||||
|
@ -40,11 +42,7 @@ extern s16 sCurrPlayMode;
|
|||
extern s16 gCurrCourseNum, gCurrActStarNum, gCurrLevelNum, gCurrAreaIndex;
|
||||
|
||||
enum NetworkType gNetworkType = NT_NONE;
|
||||
#ifdef DISCORD_SDK
|
||||
struct NetworkSystem* gNetworkSystem = &gNetworkSystemDiscord;
|
||||
#else
|
||||
struct NetworkSystem* gNetworkSystem = &gNetworkSystemSocket;
|
||||
#endif
|
||||
|
||||
#define LOADING_LEVEL_THRESHOLD 10
|
||||
#define MAX_PACKETS_PER_SECOND_PER_PLAYER ((u16)100)
|
||||
|
@ -57,7 +55,6 @@ u32 gNetworkAreaTimer = 0;
|
|||
void* gNetworkServerAddr = NULL;
|
||||
bool gNetworkSentJoin = false;
|
||||
u16 gNetworkRequestLocationTimer = 0;
|
||||
bool gDiscordReconnecting = false;
|
||||
|
||||
u8 gDebugPacketIdBuffer[256] = { 0xFF };
|
||||
u8 gDebugPacketSentBuffer[256] = { 0 };
|
||||
|
@ -80,20 +77,22 @@ struct ServerSettings gServerSettings = {
|
|||
.enablePlayersInLevelDisplay = 1,
|
||||
.enablePlayerList = 1,
|
||||
.headlessServer = 0,
|
||||
.maxPlayers = MAX_PLAYERS,
|
||||
};
|
||||
|
||||
void network_set_system(enum NetworkSystemType nsType) {
|
||||
network_forget_all_reliable();
|
||||
|
||||
switch (nsType) {
|
||||
case NS_SOCKET: gNetworkSystem = &gNetworkSystemSocket; break;
|
||||
#ifdef DISCORD_SDK
|
||||
case NS_DISCORD: gNetworkSystem = &gNetworkSystemDiscord; break;
|
||||
#ifdef COOPNET
|
||||
case NS_COOPNET: gNetworkSystem = &gNetworkSystemCoopNet; break;
|
||||
#endif
|
||||
default: LOG_ERROR("Unknown network system: %d", nsType);
|
||||
default: gNetworkSystem = &gNetworkSystemSocket; LOG_ERROR("Unknown network system: %d", nsType); break;
|
||||
}
|
||||
}
|
||||
|
||||
bool network_init(enum NetworkType inNetworkType) {
|
||||
bool network_init(enum NetworkType inNetworkType, bool reconnecting) {
|
||||
// reset override hide hud
|
||||
extern u8 gOverrideHideHud;
|
||||
gOverrideHideHud = 0;
|
||||
|
@ -116,6 +115,7 @@ bool network_init(enum NetworkType inNetworkType) {
|
|||
gServerSettings.shareLives = configShareLives;
|
||||
gServerSettings.enableCheats = configEnableCheats;
|
||||
gServerSettings.bubbleDeath = configBubbleDeath;
|
||||
gServerSettings.maxPlayers = configAmountofPlayers;
|
||||
#if defined(RAPI_DUMMY) || defined(WAPI_DUMMY)
|
||||
gServerSettings.headlessServer = (inNetworkType == NT_SERVER);
|
||||
#else
|
||||
|
@ -124,7 +124,7 @@ bool network_init(enum NetworkType inNetworkType) {
|
|||
|
||||
// initialize the network system
|
||||
gNetworkSentJoin = false;
|
||||
int rc = gNetworkSystem->initialize(inNetworkType);
|
||||
int rc = gNetworkSystem->initialize(inNetworkType, reconnecting);
|
||||
if (!rc) {
|
||||
LOG_ERROR("failed to initialize network system");
|
||||
return false;
|
||||
|
@ -155,17 +155,15 @@ bool network_init(enum NetworkType inNetworkType) {
|
|||
gChangeLevelTransition = gLevelValues.entryLevel;
|
||||
}
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
if (gNetworkSystem == &gNetworkSystemDiscord) {
|
||||
discord_activity_update(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
djui_chat_box_create();
|
||||
}
|
||||
|
||||
configfile_save(configfile_name());
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
discord_activity_update();
|
||||
#endif
|
||||
|
||||
LOG_INFO("initialized");
|
||||
|
||||
return true;
|
||||
|
@ -312,8 +310,15 @@ void network_send_to(u8 localIndex, struct Packet* p) {
|
|||
if (p->keepSendingAfterDisconnect) {
|
||||
localIndex = 0; // Force this type of packet to use the saved addr
|
||||
}
|
||||
int rc = gNetworkSystem->send(localIndex, p->addr, p->buffer, p->cursor + sizeof(u32));
|
||||
if (rc == SOCKET_ERROR) { LOG_ERROR("send error %d", rc); return; }
|
||||
u8* buffer = NULL;
|
||||
u32 len = 0;
|
||||
packet_compress(p, &buffer, &len);
|
||||
if (!buffer || len == 0) {
|
||||
LOG_ERROR("Failed to compress!");
|
||||
} else {
|
||||
int rc = gNetworkSystem->send(localIndex, p->addr, buffer, len);
|
||||
if (rc == SOCKET_ERROR) { LOG_ERROR("send error %d", rc); return; }
|
||||
}
|
||||
}
|
||||
p->sent = true;
|
||||
|
||||
|
@ -378,14 +383,16 @@ void network_receive(u8 localIndex, void* addr, u8* data, u16 dataLength) {
|
|||
.buffer = { 0 },
|
||||
.dataLength = dataLength,
|
||||
};
|
||||
memcpy(p.buffer, data, dataLength);
|
||||
if (!packet_decompress(&p, data, dataLength)) {
|
||||
LOG_ERROR("Failed to decompress!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (localIndex != UNKNOWN_LOCAL_INDEX && localIndex != 0) {
|
||||
gNetworkPlayers[localIndex].lastReceived = clock_elapsed();
|
||||
}
|
||||
|
||||
// subtract and check hash
|
||||
p.dataLength -= sizeof(u32);
|
||||
if (!packet_check_hash(&p)) {
|
||||
LOG_ERROR("invalid packet hash!");
|
||||
return;
|
||||
|
@ -407,7 +414,6 @@ void network_reset_reconnect_and_rehost(void) {
|
|||
sNetworkReconnectTimer = 0;
|
||||
sNetworkRehostTimer = 0;
|
||||
sNetworkReconnectType = NS_SOCKET;
|
||||
gDiscordReconnecting = false;
|
||||
}
|
||||
|
||||
void network_reconnect_begin(void) {
|
||||
|
@ -417,17 +423,15 @@ void network_reconnect_begin(void) {
|
|||
|
||||
sNetworkReconnectTimer = 2 * 30;
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
sNetworkReconnectType = (gNetworkSystem == &gNetworkSystemDiscord)
|
||||
? NS_DISCORD
|
||||
#ifdef COOPNET
|
||||
sNetworkReconnectType = (gNetworkSystem == &gNetworkSystemCoopNet)
|
||||
? NS_COOPNET
|
||||
: NS_SOCKET;
|
||||
#else
|
||||
sNetworkReconnectType = NS_SOCKET;
|
||||
#endif
|
||||
|
||||
gDiscordReconnecting = true;
|
||||
network_shutdown(false, false, false);
|
||||
gDiscordReconnecting = false;
|
||||
network_shutdown(false, false, false, true);
|
||||
|
||||
djui_connect_menu_open();
|
||||
}
|
||||
|
@ -438,11 +442,11 @@ static void network_reconnect_update(void) {
|
|||
|
||||
if (sNetworkReconnectType == NS_SOCKET) {
|
||||
network_set_system(NS_SOCKET);
|
||||
} else if (sNetworkReconnectType == NS_COOPNET) {
|
||||
network_set_system(NS_COOPNET);
|
||||
}
|
||||
|
||||
gDiscordReconnecting = true;
|
||||
network_init(NT_CLIENT);
|
||||
gDiscordReconnecting = false;
|
||||
network_init(NT_CLIENT, true);
|
||||
|
||||
network_send_mod_list_request();
|
||||
}
|
||||
|
@ -460,21 +464,17 @@ void network_rehost_begin(void) {
|
|||
network_player_disconnected(i);
|
||||
}
|
||||
|
||||
gDiscordReconnecting = true;
|
||||
network_shutdown(false, false, false);
|
||||
gDiscordReconnecting = false;
|
||||
network_shutdown(false, false, false, true);
|
||||
|
||||
sNetworkRehostTimer = 2;
|
||||
}
|
||||
|
||||
static void network_rehost_update(void) {
|
||||
extern void djui_panel_do_host(void);
|
||||
extern void djui_panel_do_host(bool reconnecting);
|
||||
if (sNetworkRehostTimer <= 0) { return; }
|
||||
if (--sNetworkRehostTimer != 0) { return; }
|
||||
|
||||
gDiscordReconnecting = true;
|
||||
djui_panel_do_host();
|
||||
gDiscordReconnecting = false;
|
||||
djui_panel_do_host(true);
|
||||
}
|
||||
|
||||
static void network_update_area_timer(void) {
|
||||
|
@ -509,8 +509,15 @@ static void network_update_area_timer(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void network_update(void) {
|
||||
#ifdef COOPNET
|
||||
void network_update_coopnet(void) {
|
||||
if (gNetworkType != NT_NONE) { return; }
|
||||
if (!ns_coopnet_is_connected()) { return; }
|
||||
ns_coopnet_update();
|
||||
}
|
||||
#endif
|
||||
|
||||
void network_update(void) {
|
||||
if (gNetworkStartupTimer > 0) {
|
||||
gNetworkStartupTimer--;
|
||||
}
|
||||
|
@ -518,6 +525,10 @@ void network_update(void) {
|
|||
network_rehost_update();
|
||||
network_reconnect_update();
|
||||
|
||||
#ifdef COOPNET
|
||||
network_update_coopnet();
|
||||
#endif
|
||||
|
||||
// check for level loaded event
|
||||
if (networkLoadingLevel < LOADING_LEVEL_THRESHOLD) {
|
||||
networkLoadingLevel++;
|
||||
|
@ -585,7 +596,7 @@ void network_register_mod(char* modName) {
|
|||
string_linked_list_append(&gRegisteredMods, modName);
|
||||
}
|
||||
|
||||
void network_shutdown(bool sendLeaving, bool exiting, bool popup) {
|
||||
void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnecting) {
|
||||
if (gDjuiChatBox != NULL) {
|
||||
djui_base_destroy(&gDjuiChatBox->base);
|
||||
gDjuiChatBox = NULL;
|
||||
|
@ -599,7 +610,7 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup) {
|
|||
|
||||
if (gNetworkPlayerLocal != NULL && sendLeaving) { network_send_leaving(gNetworkPlayerLocal->globalIndex); }
|
||||
network_player_shutdown(popup);
|
||||
gNetworkSystem->shutdown();
|
||||
gNetworkSystem->shutdown(reconnecting);
|
||||
|
||||
if (gNetworkServerAddr != NULL) {
|
||||
free(gNetworkServerAddr);
|
||||
|
@ -607,15 +618,10 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup) {
|
|||
}
|
||||
gNetworkPlayerServer = NULL;
|
||||
|
||||
if (sNetworkReconnectTimer <= 0 || sNetworkReconnectType != NS_DISCORD) {
|
||||
if (sNetworkReconnectTimer <= 0 || sNetworkReconnectType != NS_COOPNET) {
|
||||
gNetworkType = NT_NONE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
network_set_system(NS_DISCORD);
|
||||
#endif
|
||||
|
||||
if (exiting) { return; }
|
||||
|
||||
// reset other stuff
|
||||
|
@ -627,6 +633,9 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup) {
|
|||
gOverrideNear = 0;
|
||||
gOverrideFar = 0;
|
||||
gOverrideFOV = 0;
|
||||
gCurrActStarNum = 0;
|
||||
gCurrActNum = 0;
|
||||
gCurrCreditsEntry = NULL;
|
||||
gLightingDir[0] = 0;
|
||||
gLightingDir[1] = 0;
|
||||
gLightingDir[2] = 0;
|
||||
|
@ -677,4 +686,9 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup) {
|
|||
gDjuiInMainMenu = true;
|
||||
djui_panel_main_create(NULL);
|
||||
}
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
discord_activity_update();
|
||||
#endif
|
||||
packet_ordered_clear_all();
|
||||
}
|
||||
|
|
|
@ -36,11 +36,12 @@ extern struct MarioState gMarioStates[];
|
|||
|
||||
enum NetworkSystemType {
|
||||
NS_SOCKET,
|
||||
NS_DISCORD,
|
||||
NS_COOPNET,
|
||||
NS_MAX,
|
||||
};
|
||||
|
||||
struct NetworkSystem {
|
||||
bool (*initialize)(enum NetworkType);
|
||||
bool (*initialize)(enum NetworkType, bool reconnecting);
|
||||
s64 (*get_id)(u8 localIndex);
|
||||
char* (*get_id_str)(u8 localIndex);
|
||||
void (*save_id)(u8 localIndex, s64 networkId);
|
||||
|
@ -49,7 +50,9 @@ struct NetworkSystem {
|
|||
bool (*match_addr)(void* addr1, void* addr2);
|
||||
void (*update)(void);
|
||||
int (*send)(u8 localIndex, void* addr, u8* data, u16 dataLength);
|
||||
void (*shutdown)(void);
|
||||
void (*get_lobby_id)(char* destination, u32 destLength);
|
||||
void (*get_lobby_secret)(char* destination, u32 destLength);
|
||||
void (*shutdown)(bool reconnecting);
|
||||
bool requireServerBroadcast;
|
||||
char* name;
|
||||
};
|
||||
|
@ -71,6 +74,7 @@ struct ServerSettings {
|
|||
u8 enablePlayersInLevelDisplay;
|
||||
u8 enablePlayerList;
|
||||
u8 headlessServer;
|
||||
u8 maxPlayers;
|
||||
};
|
||||
|
||||
// Networking-specific externs
|
||||
|
@ -89,11 +93,10 @@ extern u8 gDebugPacketIdBuffer[];
|
|||
extern u8 gDebugPacketSentBuffer[];
|
||||
extern u8 gDebugPacketOnBuffer;
|
||||
extern u32 gNetworkStartupTimer;
|
||||
extern bool gDiscordReconnecting;
|
||||
|
||||
// network.c
|
||||
void network_set_system(enum NetworkSystemType nsType);
|
||||
bool network_init(enum NetworkType inNetworkType);
|
||||
bool network_init(enum NetworkType inNetworkType, bool reconnecting);
|
||||
void network_on_init_area(void);
|
||||
void network_on_loaded_area(void);
|
||||
bool network_allow_unknown_local_index(enum PacketType packetType);
|
||||
|
@ -107,6 +110,6 @@ bool network_is_reconnecting(void);
|
|||
void network_rehost_begin(void);
|
||||
void network_update(void);
|
||||
void network_register_mod(char* modName);
|
||||
void network_shutdown(bool sendLeaving, bool exiting, bool popup);
|
||||
void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnecting);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,11 @@
|
|||
#include "game/hardcoded.h"
|
||||
#include "game/object_helpers.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
#include "pc/network/socket/socket.h"
|
||||
#include "lag_compensation.h"
|
||||
#ifdef DISCORD_SDK
|
||||
#include "pc/discord/discord.h"
|
||||
#endif
|
||||
|
||||
struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 };
|
||||
struct NetworkPlayer *gNetworkPlayerLocal = NULL;
|
||||
|
@ -176,13 +180,15 @@ void network_player_update(void) {
|
|||
if (!np->connected && i > 0) { continue; }
|
||||
|
||||
float elapsed = (clock_elapsed() - np->lastReceived);
|
||||
#ifndef DEVELOPMENT
|
||||
#ifdef DEVELOPMENT
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT && (gNetworkSystem != &gNetworkSystemSocket)) {
|
||||
#else
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT) {
|
||||
#endif
|
||||
LOG_INFO("dropping player %d", i);
|
||||
network_player_disconnected(i);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
elapsed = (clock_elapsed() - np->lastSent);
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT / 3.0f) {
|
||||
network_send_keep_alive(np->localIndex);
|
||||
|
@ -193,12 +199,14 @@ void network_player_update(void) {
|
|||
if (!np->connected) { return; }
|
||||
float elapsed = (clock_elapsed() - np->lastReceived);
|
||||
|
||||
#ifndef DEVELOPMENT
|
||||
#ifdef DEVELOPMENT
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT * 1.5f && (gNetworkSystem != &gNetworkSystemSocket)) {
|
||||
#else
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT * 1.5f) {
|
||||
LOG_INFO("dropping due to no server connectivity");
|
||||
network_shutdown(false, false, true);
|
||||
}
|
||||
#endif
|
||||
LOG_INFO("dropping due to no server connectivity");
|
||||
network_shutdown(false, false, true, false);
|
||||
}
|
||||
|
||||
elapsed = (clock_elapsed() - np->lastSent);
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT / 3.0f) {
|
||||
|
@ -254,7 +262,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
|
|||
np->type = type;
|
||||
np->localIndex = localIndex;
|
||||
np->globalIndex = globalIndex;
|
||||
np->ping = 50;
|
||||
np->ping = 600;
|
||||
if ((type != NPT_LOCAL) && (gNetworkType == NT_SERVER || type == NPT_SERVER)) { gNetworkSystem->save_id(localIndex, 0); }
|
||||
network_player_set_description(np, NULL, 0, 0, 0, 0);
|
||||
|
||||
|
@ -291,7 +299,6 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
|
|||
}
|
||||
|
||||
for (s32 j = 0; j < MAX_RX_SEQ_IDS; j++) { np->rxSeqIds[j] = 0; np->rxPacketHash[j] = 0; }
|
||||
packet_ordered_clear(globalIndex);
|
||||
|
||||
// set up network player pointers
|
||||
if (type == NPT_LOCAL) {
|
||||
|
@ -311,6 +318,9 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
|
|||
|
||||
smlua_call_event_hooks_mario_param(HOOK_ON_PLAYER_CONNECTED, &gMarioStates[localIndex]);
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
discord_activity_update();
|
||||
#endif
|
||||
|
||||
return localIndex;
|
||||
}
|
||||
|
@ -321,7 +331,7 @@ u8 network_player_disconnected(u8 globalIndex) {
|
|||
LOG_ERROR("player disconnected, but it's local.. this shouldn't happen!");
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
} else {
|
||||
network_shutdown(true, false, true);
|
||||
network_shutdown(true, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,6 +370,10 @@ u8 network_player_disconnected(u8 globalIndex) {
|
|||
|
||||
memset(np, 0, sizeof(struct NetworkPlayer));
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
discord_activity_update();
|
||||
#endif
|
||||
|
||||
return i;
|
||||
}
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
|
@ -428,7 +442,7 @@ void network_player_update_course_level(struct NetworkPlayer* np, s16 courseNum,
|
|||
}
|
||||
|
||||
// If this machine's player changed to a different location, then all of the other np locations are no longer valid
|
||||
for (u32 i = 1; i < configAmountofPlayers; i++) {
|
||||
for (u32 i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* npi = &gNetworkPlayers[i];
|
||||
if ((!npi->connected) || npi == gNetworkPlayerLocal) { continue; }
|
||||
npi->currPositionValid = false;
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
#define UNKNOWN_LOCAL_INDEX ((u8)-1)
|
||||
#define UNKNOWN_GLOBAL_INDEX ((u8)-1)
|
||||
#define UNKNOWN_NETWORK_INDEX ((u64)-1)
|
||||
#define NETWORK_PLAYER_TIMEOUT 10
|
||||
#define NETWORK_PLAYER_PING_TIMEOUT 1
|
||||
#define MAX_RX_SEQ_IDS 64
|
||||
#define NETWORK_PLAYER_TIMEOUT 15
|
||||
#define NETWORK_PLAYER_PING_TIMEOUT 3
|
||||
#define MAX_RX_SEQ_IDS 256
|
||||
#define USE_REAL_PALETTE_VAR 0xFF
|
||||
|
||||
enum NetworkPlayerType {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include "network_utils.h"
|
||||
#include "discord/discord.h"
|
||||
#include "game/mario_misc.h"
|
||||
|
||||
u8 network_global_index_from_local(u8 localIndex) {
|
||||
|
@ -23,15 +22,6 @@ u8 network_local_index_from_global(u8 globalIndex) {
|
|||
return globalIndex + ((globalIndex < gNetworkPlayerLocal->globalIndex) ? 1 : 0);
|
||||
}
|
||||
|
||||
#ifdef DISCORD_SDK
|
||||
char* network_discord_id_from_local_index(u8 localIndex) {
|
||||
if (gNetworkSystem == &gNetworkSystemDiscord) { return gNetworkSystem->get_id_str(localIndex); }
|
||||
#else
|
||||
char* network_discord_id_from_local_index(UNUSED u8 localIndex) {
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool network_is_server(void) {
|
||||
return gNetworkType == NT_SERVER;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
u8 network_global_index_from_local(u8 localIndex);
|
||||
u8 network_local_index_from_global(u8 globalIndex);
|
||||
|
||||
char* network_discord_id_from_local_index(u8 localIndex);
|
||||
|
||||
bool network_is_server(void);
|
||||
bool network_is_moderator(void);
|
||||
|
||||
|
|
|
@ -1,8 +1,47 @@
|
|||
#include <stdio.h>
|
||||
#include <zlib.h>
|
||||
#include "../network.h"
|
||||
#include "pc/network/ban_list.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
static u32 sCompBufferLen = 0;
|
||||
static Bytef* sCompBuffer = NULL;
|
||||
|
||||
static void increase_comp_buffer(u32 compressedLen) {
|
||||
if (compressedLen <= sCompBufferLen && sCompBuffer) { return; }
|
||||
|
||||
if (sCompBuffer != NULL) { free(sCompBuffer); }
|
||||
|
||||
sCompBufferLen = compressedLen;
|
||||
sCompBuffer = (Bytef*)malloc(sCompBufferLen);
|
||||
}
|
||||
|
||||
void packet_compress(struct Packet* p, u8** compBuffer, u32* compSize) {
|
||||
uLong sourceSize = p->dataLength + sizeof(u32);
|
||||
uLongf compressedLen = compressBound(sourceSize);
|
||||
increase_comp_buffer(PACKET_LENGTH);
|
||||
|
||||
if (sCompBuffer && compress2((Bytef*)sCompBuffer, &compressedLen, (Bytef*)p->buffer, sourceSize, Z_BEST_COMPRESSION) == Z_OK) {
|
||||
*compBuffer = sCompBuffer;
|
||||
*compSize = compressedLen;
|
||||
} else {
|
||||
*compBuffer = NULL;
|
||||
*compSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool packet_decompress(struct Packet* p, u8* compBuffer, u32 compSize) {
|
||||
increase_comp_buffer(PACKET_LENGTH);
|
||||
if (!sCompBuffer) { return false; }
|
||||
uLong decompSize = PACKET_LENGTH;
|
||||
if (uncompress((Bytef*)p->buffer, &decompSize, (Bytef*)compBuffer, compSize) == Z_OK) {
|
||||
p->dataLength = decompSize - sizeof(u32);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void packet_process(struct Packet* p) {
|
||||
if (gNetworkType == NT_NONE) { return; }
|
||||
if (p->levelAreaMustMatch) {
|
||||
|
@ -156,7 +195,7 @@ void packet_receive(struct Packet* p) {
|
|||
np->rxSeqIds[np->onRxSeqId] = p->seqId;
|
||||
np->rxPacketHash[np->onRxSeqId] = packetHash;
|
||||
np->onRxSeqId++;
|
||||
if (np->onRxSeqId >= MAX_RX_SEQ_IDS) { np->onRxSeqId = 0; }
|
||||
//if (np->onRxSeqId >= MAX_RX_SEQ_IDS) { np->onRxSeqId = 0; }
|
||||
}
|
||||
|
||||
// parse the packet without processing the rest
|
||||
|
|
|
@ -102,8 +102,8 @@ struct Packet {
|
|||
u16 seqId;
|
||||
bool sent;
|
||||
u8 orderedFromGlobalId;
|
||||
u8 orderedGroupId;
|
||||
u8 orderedSeqId;
|
||||
u16 orderedGroupId;
|
||||
u16 orderedSeqId;
|
||||
u8 courseNum;
|
||||
u8 actNum;
|
||||
u8 levelNum;
|
||||
|
@ -147,7 +147,11 @@ struct LSTNetworkType {
|
|||
size_t size;
|
||||
};
|
||||
|
||||
extern u8 gAllowOrderedPacketClear;
|
||||
|
||||
// packet.c
|
||||
void packet_compress(struct Packet* p, u8** compBuffer, u32* compSize);
|
||||
bool packet_decompress(struct Packet* p, u8* compBuffer, u32 compSize);
|
||||
void packet_process(struct Packet* p);
|
||||
void packet_receive(struct Packet* packet);
|
||||
bool packet_spoofed(struct Packet* p, u8 globalIndex);
|
||||
|
@ -164,6 +168,7 @@ u32 packet_hash(struct Packet* packet);
|
|||
bool packet_check_hash(struct Packet* packet);
|
||||
void packet_ordered_begin(void);
|
||||
void packet_ordered_end(void);
|
||||
void packet_ordered_clear_all(void);
|
||||
void packet_set_ordered_data(struct Packet* packet);
|
||||
|
||||
// packet_reliable.c
|
||||
|
@ -176,7 +181,7 @@ void network_update_reliable(void);
|
|||
|
||||
// packet_ordered.c
|
||||
void packet_ordered_add(struct Packet* p);
|
||||
void packet_ordered_clear_table(u8 globalIndex, u8 groupdId);
|
||||
void packet_ordered_clear_table(u8 globalIndex, u16 groupdId);
|
||||
void packet_ordered_clear(u8 globalIndex);
|
||||
void packet_ordered_update(void);
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ void network_send_join(struct Packet* joinRequestPacket) {
|
|||
// figure out id
|
||||
u8 globalIndex = joinRequestPacket->localIndex;
|
||||
if (globalIndex == UNKNOWN_LOCAL_INDEX) {
|
||||
for (u32 i = 1; i < configAmountofPlayers; i++) {
|
||||
for (u32 i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (!gNetworkPlayers[i].connected) {
|
||||
globalIndex = i;
|
||||
break;
|
||||
|
@ -119,6 +119,7 @@ void network_send_join(struct Packet* joinRequestPacket) {
|
|||
packet_write(&p, &gServerSettings.enableCheats, sizeof(u8));
|
||||
packet_write(&p, &gServerSettings.bubbleDeath, sizeof(u8));
|
||||
packet_write(&p, &gServerSettings.headlessServer, sizeof(u8));
|
||||
packet_write(&p, &gServerSettings.maxPlayers, sizeof(u8));
|
||||
packet_write(&p, eeprom, sizeof(u8) * 512);
|
||||
|
||||
u8 modCount = string_linked_list_count(&gRegisteredMods);
|
||||
|
@ -165,7 +166,7 @@ void network_receive_join(struct Packet* p) {
|
|||
packet_read(p, &remoteVersion, sizeof(u8) * MAX_VERSION_LENGTH);
|
||||
LOG_INFO("server has version: %s", version);
|
||||
if (memcmp(version, remoteVersion, MAX_VERSION_LENGTH) != 0) {
|
||||
network_shutdown(true, false, false);
|
||||
network_shutdown(true, false, false, false);
|
||||
LOG_ERROR("version mismatch");
|
||||
char mismatchMessage[256] = { 0 };
|
||||
snprintf(mismatchMessage, 256, "\\#ffa0a0\\Error:\\#c8c8c8\\ Version mismatch.\n\nYour version: \\#a0a0ff\\%s\\#c8c8c8\\\nTheir version: \\#a0a0ff\\%s\\#c8c8c8\\\n\nSomeone is out of date!\n", version, remoteVersion);
|
||||
|
@ -183,6 +184,7 @@ void network_receive_join(struct Packet* p) {
|
|||
packet_read(p, &gServerSettings.enableCheats, sizeof(u8));
|
||||
packet_read(p, &gServerSettings.bubbleDeath, sizeof(u8));
|
||||
packet_read(p, &gServerSettings.headlessServer, sizeof(u8));
|
||||
packet_read(p, &gServerSettings.maxPlayers, sizeof(u8));
|
||||
packet_read(p, eeprom, sizeof(u8) * 512);
|
||||
packet_read(p, &modCount, sizeof(u8));
|
||||
|
||||
|
@ -196,7 +198,7 @@ void network_receive_join(struct Packet* p) {
|
|||
}
|
||||
|
||||
if (string_linked_list_mismatch(&gRegisteredMods, &head)) {
|
||||
network_shutdown(true, false, false);
|
||||
network_shutdown(true, false, false, false);
|
||||
|
||||
struct StringBuilder* builder = string_builder_create(512);
|
||||
string_builder_append(builder, "\\#ffa0a0\\Error:\\#c8c8c8\\ mods don't match.\n\n");
|
||||
|
@ -253,4 +255,6 @@ void network_receive_join(struct Packet* p) {
|
|||
smlua_call_event_hooks(HOOK_JOINED_GAME);
|
||||
extern s16 gChangeLevel;
|
||||
gChangeLevel = gLevelValues.entryLevel;
|
||||
|
||||
gAllowOrderedPacketClear = 1;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
#include "pc/djui/djui.h"
|
||||
#include "pc/utils/misc.h"
|
||||
|
||||
f32 lastReconnectTime = -9999999;
|
||||
f32 sLastReconnectTime = -9999999;
|
||||
f32 sLastNotifyTime = -9999999;
|
||||
|
||||
void network_send_kick(u8 localIndex, enum KickReasonType kickReason) {
|
||||
u8 kickReasonType = kickReason;
|
||||
|
@ -30,21 +31,24 @@ void network_receive_kick(struct Packet* p) {
|
|||
packet_read(p, &kickReasonType, sizeof(u8));
|
||||
enum KickReasonType kickReason = kickReasonType;
|
||||
|
||||
switch (kickReason) {
|
||||
case EKT_FULL_PARTY: djui_popup_create(DLANG(NOTIF, DISCONNECT_FULL), 1); break;
|
||||
case EKT_KICKED: djui_popup_create(DLANG(NOTIF, DISCONNECT_KICK), 1); break;
|
||||
case EKT_BANNED: djui_popup_create(DLANG(NOTIF, DISCONNECT_BAN), 1); break;
|
||||
default: djui_popup_create(DLANG(NOTIF, DISCONNECT_CLOSED), 1); break;
|
||||
f32 now = clock_elapsed();
|
||||
if ((now - sLastNotifyTime) > 3) {
|
||||
sLastNotifyTime = now;
|
||||
switch (kickReason) {
|
||||
case EKT_FULL_PARTY: djui_popup_create(DLANG(NOTIF, DISCONNECT_FULL), 1); break;
|
||||
case EKT_KICKED: djui_popup_create(DLANG(NOTIF, DISCONNECT_KICK), 1); break;
|
||||
case EKT_BANNED: djui_popup_create(DLANG(NOTIF, DISCONNECT_BAN), 1); break;
|
||||
default: djui_popup_create(DLANG(NOTIF, DISCONNECT_CLOSED), 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (kickReason == EKT_REJOIN) {
|
||||
f32 now = clock_elapsed();
|
||||
if ((now - lastReconnectTime) > 3) {
|
||||
lastReconnectTime = now;
|
||||
if ((now - sLastReconnectTime) > 3) {
|
||||
sLastReconnectTime = now;
|
||||
network_reconnect_begin();
|
||||
djui_popup_create(DLANG(NOTIF, DISCONNECT_REJOIN), 1);
|
||||
}
|
||||
} else {
|
||||
network_shutdown(false, false, false);
|
||||
network_shutdown(false, false, false, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ void network_send_mod_list_request(void) {
|
|||
|
||||
network_send_to(PACKET_DESTINATION_SERVER, &p);
|
||||
LOG_INFO("sending mod list request");
|
||||
gAllowOrderedPacketClear = 0;
|
||||
}
|
||||
|
||||
void network_receive_mod_list_request(UNUSED struct Packet* p) {
|
||||
|
@ -140,7 +141,7 @@ void network_receive_mod_list(struct Packet* p) {
|
|||
packet_read(p, &remoteVersion, sizeof(u8) * MAX_VERSION_LENGTH);
|
||||
LOG_INFO("server has version: %s", version);
|
||||
if (memcmp(version, remoteVersion, MAX_VERSION_LENGTH) != 0) {
|
||||
network_shutdown(true, false, false);
|
||||
network_shutdown(true, false, false, false);
|
||||
LOG_ERROR("version mismatch");
|
||||
char mismatchMessage[256] = { 0 };
|
||||
snprintf(mismatchMessage, 256, "\\#ffa0a0\\Error:\\#c8c8c8\\ Version mismatch.\n\nYour version: \\#a0a0ff\\%s\\#c8c8c8\\\nTheir version: \\#a0a0ff\\%s\\#c8c8c8\\\n\nSomeone is out of date!\n", version, remoteVersion);
|
||||
|
@ -241,7 +242,7 @@ void network_receive_mod_list_entry(struct Packet* p) {
|
|||
// sanity check mod size
|
||||
if (mod->size >= MAX_MOD_SIZE) {
|
||||
djui_popup_create(DLANG(NOTIF, DISCONNECT_BIG_MOD), 4);
|
||||
network_shutdown(false, false, false);
|
||||
network_shutdown(false, false, false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <stdio.h>
|
||||
#include "../network.h"
|
||||
#include "pc/utils/misc.h"
|
||||
#define DISABLE_MODULE_LOG 1
|
||||
//#define DISABLE_MODULE_LOG 1
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
#define PACKET_ORDERED_TIMEOUT 15
|
||||
#define PACKET_ORDERED_TIMEOUT 30
|
||||
|
||||
struct OrderedPacketList {
|
||||
struct Packet p;
|
||||
|
@ -13,14 +13,15 @@ struct OrderedPacketList {
|
|||
|
||||
struct OrderedPacketTable {
|
||||
u8 fromGlobalId;
|
||||
u8 groupId;
|
||||
u8 processSeqId;
|
||||
u16 groupId;
|
||||
u16 processSeqId;
|
||||
f32 lastReceived;
|
||||
struct OrderedPacketList* packets;
|
||||
struct OrderedPacketTable* next;
|
||||
};
|
||||
|
||||
static struct OrderedPacketTable* orderedPacketTable[MAX_PLAYERS] = { 0 };
|
||||
u8 gAllowOrderedPacketClear = 1;
|
||||
|
||||
static void packet_ordered_check_for_processing(struct OrderedPacketTable* opt) {
|
||||
// sanity check
|
||||
|
@ -159,7 +160,7 @@ void packet_ordered_add(struct Packet* p) {
|
|||
packet_ordered_add_to_table(opt, p);
|
||||
}
|
||||
|
||||
void packet_ordered_clear_table(u8 globalIndex, u8 groupId) {
|
||||
void packet_ordered_clear_table(u8 globalIndex, u16 groupId) {
|
||||
LOG_INFO("clearing out ordered packet table for %d (%d)", globalIndex, groupId);
|
||||
|
||||
struct OrderedPacketTable* opt = orderedPacketTable[globalIndex];
|
||||
|
@ -196,6 +197,11 @@ void packet_ordered_clear_table(u8 globalIndex, u8 groupId) {
|
|||
}
|
||||
|
||||
void packet_ordered_clear(u8 globalIndex) {
|
||||
if (!gAllowOrderedPacketClear) {
|
||||
LOG_INFO("disallowed ordered packets to be cleared");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("clearing out all ordered packet tables for %d", globalIndex);
|
||||
struct OrderedPacketTable* opt = orderedPacketTable[globalIndex];
|
||||
|
||||
|
@ -219,6 +225,14 @@ void packet_ordered_clear(u8 globalIndex) {
|
|||
orderedPacketTable[globalIndex] = NULL;
|
||||
}
|
||||
|
||||
|
||||
void packet_ordered_clear_all(void) {
|
||||
gAllowOrderedPacketClear = 1;
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) {
|
||||
packet_ordered_clear(i);
|
||||
}
|
||||
}
|
||||
|
||||
void packet_ordered_update(void) {
|
||||
f32 currentClock = clock_elapsed();
|
||||
// check all ordered tables for a time out
|
||||
|
|
|
@ -14,11 +14,11 @@ void network_send_ping(struct NetworkPlayer* toNp) {
|
|||
packet_write(&p, ×tamp, sizeof(f64));
|
||||
network_send_to(toNp->localIndex, &p);
|
||||
|
||||
//LOG_INFO("tx ping");
|
||||
LOG_INFO("tx ping");
|
||||
}
|
||||
|
||||
void network_receive_ping(struct Packet* p) {
|
||||
//LOG_INFO("rx ping");
|
||||
LOG_INFO("rx ping");
|
||||
|
||||
u8 globalIndex;
|
||||
f64 timestamp;
|
||||
|
|
|
@ -403,9 +403,33 @@ void network_receive_player(struct Packet* p) {
|
|||
|
||||
void network_update_player(void) {
|
||||
if (!network_player_any_connected()) { return; }
|
||||
struct MarioState* m = &gMarioStates[0];
|
||||
|
||||
u8 localIsHeadless = (&gNetworkPlayers[0] == gNetworkPlayerServer && gServerSettings.headlessServer);
|
||||
if (!localIsHeadless) {
|
||||
network_send_player(0);
|
||||
}
|
||||
if (localIsHeadless) { return; }
|
||||
|
||||
// figure out if we should send it or not
|
||||
static u8 sTicksSinceSend = 0;
|
||||
static u32 sLastPlayerAction = 0;
|
||||
static f32 sLastStickX = 0;
|
||||
static f32 sLastStickY = 0;
|
||||
static u32 sLastButtonDown = 0;
|
||||
static u32 sLastButtonPressed = 0;
|
||||
|
||||
f32 stickDist = sqrtf(powf(sLastStickX - m->controller->stickX, 2) + powf(sLastStickY - m->controller->stickY, 2));
|
||||
bool shouldSend = (sTicksSinceSend > 2)
|
||||
|| (sLastPlayerAction != m->action)
|
||||
|| (sLastButtonDown != m->controller->buttonDown)
|
||||
|| (sLastButtonPressed != m->controller->buttonPressed)
|
||||
|| (stickDist > 5.0f);
|
||||
|
||||
if (!shouldSend) { sTicksSinceSend++; return; }
|
||||
network_send_player(0);
|
||||
sTicksSinceSend = 0;
|
||||
|
||||
sLastPlayerAction = m->action;
|
||||
sLastStickX = m->controller->stickX;
|
||||
sLastStickY = m->controller->stickY;
|
||||
sLastButtonDown = m->controller->buttonDown;
|
||||
sLastButtonPressed = m->controller->buttonPressed;
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
#define PACKET_FLAG_BUFFER_OFFSET 3
|
||||
#define PACKET_DESTINATION_BUFFER_OFFSET 4
|
||||
#define PACKET_ORDERED_SEQ_ID_OFFSET 7
|
||||
#define PACKET_ORDERED_SEQ_ID_OFFSET 8
|
||||
|
||||
static u16 sNextSeqNum = 1;
|
||||
|
||||
static bool sOrderedPackets = false;
|
||||
static u8 sCurrentOrderedGroupId = 0;
|
||||
static u8 sCurrentOrderedSeqId = 0;
|
||||
static u16 sCurrentOrderedGroupId = 0;
|
||||
static u16 sCurrentOrderedSeqId = 0;
|
||||
|
||||
void packet_init(struct Packet* packet, enum PacketType packetType, bool reliable, enum PacketLevelMatchType levelAreaMustMatch) {
|
||||
memset(packet->buffer, 0, PACKET_LENGTH);
|
||||
|
@ -54,8 +54,8 @@ void packet_init(struct Packet* packet, enum PacketType packetType, bool reliabl
|
|||
// write ordered packet information
|
||||
if (sOrderedPackets) {
|
||||
packet_write(packet, &packet->orderedFromGlobalId, sizeof(u8));
|
||||
packet_write(packet, &packet->orderedGroupId, sizeof(u8));
|
||||
packet_write(packet, &packet->orderedSeqId, sizeof(u8));
|
||||
packet_write(packet, &packet->orderedGroupId, sizeof(u16));
|
||||
packet_write(packet, &packet->orderedSeqId, sizeof(u16));
|
||||
}
|
||||
|
||||
// write location
|
||||
|
@ -162,8 +162,8 @@ u8 packet_initial_read(struct Packet* packet) {
|
|||
// read ordered packet information
|
||||
if (packetIsOrdered) {
|
||||
packet_read(packet, &packet->orderedFromGlobalId, sizeof(u8));
|
||||
packet_read(packet, &packet->orderedGroupId, sizeof(u8));
|
||||
packet_read(packet, &packet->orderedSeqId, sizeof(u8));
|
||||
packet_read(packet, &packet->orderedGroupId, sizeof(u16));
|
||||
packet_read(packet, &packet->orderedSeqId, sizeof(u16));
|
||||
}
|
||||
|
||||
// read location
|
||||
|
@ -231,5 +231,6 @@ void packet_set_ordered_data(struct Packet* packet) {
|
|||
if (packet->orderedGroupId == 0) { return; }
|
||||
if (packet->orderedSeqId != 0) { return; }
|
||||
packet->orderedSeqId = sCurrentOrderedSeqId++;
|
||||
packet->buffer[PACKET_ORDERED_SEQ_ID_OFFSET] = packet->orderedSeqId;
|
||||
u16* seqId = (u16*)&packet->buffer[PACKET_ORDERED_SEQ_ID_OFFSET];
|
||||
*seqId = packet->orderedSeqId;
|
||||
}
|
|
@ -35,6 +35,7 @@ static void remove_node_from_list(struct PacketLinkedList* node) {
|
|||
}
|
||||
|
||||
void network_forget_all_reliable(void) {
|
||||
LOG_INFO("Clearing all reliable!");
|
||||
struct PacketLinkedList* node = head;
|
||||
while (node != NULL) {
|
||||
struct PacketLinkedList* next = node->next;
|
||||
|
@ -47,6 +48,7 @@ void network_forget_all_reliable(void) {
|
|||
|
||||
void network_forget_all_reliable_from(u8 localIndex) {
|
||||
if (localIndex == 0) { return; }
|
||||
LOG_INFO("Clearing all reliable from %u", localIndex);
|
||||
struct PacketLinkedList* node = head;
|
||||
while (node != NULL) {
|
||||
struct PacketLinkedList* next = node->next;
|
||||
|
|
|
@ -59,7 +59,7 @@ static int socket_receive(SOCKET socket, struct sockaddr_in* rxAddr, u8* buffer,
|
|||
return NO_ERROR;
|
||||
}
|
||||
|
||||
static bool ns_socket_initialize(enum NetworkType networkType) {
|
||||
static bool ns_socket_initialize(enum NetworkType networkType, UNUSED bool reconnecting) {
|
||||
|
||||
// sanity check port
|
||||
unsigned int port = (networkType == NT_CLIENT) ? configJoinPort : configHostPort;
|
||||
|
@ -180,7 +180,15 @@ static int ns_socket_send(u8 localIndex, void* address, u8* data, u16 dataLength
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void ns_socket_shutdown(void) {
|
||||
static void ns_socket_get_lobby_id(char* destination, u32 destLength) {
|
||||
snprintf(destination, destLength, "%s", ""); // TODO: we can probably hook this up
|
||||
}
|
||||
|
||||
static void ns_socket_get_lobby_secret(char* destination, u32 destLength) {
|
||||
snprintf(destination, destLength, "%s", ""); // TODO: we can probably hook this up
|
||||
}
|
||||
|
||||
static void ns_socket_shutdown(UNUSED bool reconnecting) {
|
||||
socket_shutdown(sCurSocket);
|
||||
sCurSocket = INVALID_SOCKET;
|
||||
for (u16 i = 0; i < MAX_PLAYERS; i++) {
|
||||
|
@ -190,16 +198,18 @@ static void ns_socket_shutdown(void) {
|
|||
}
|
||||
|
||||
struct NetworkSystem gNetworkSystemSocket = {
|
||||
.initialize = ns_socket_initialize,
|
||||
.get_id = ns_socket_get_id,
|
||||
.get_id_str = ns_socket_get_id_str,
|
||||
.save_id = ns_socket_save_id,
|
||||
.clear_id = ns_socket_clear_id,
|
||||
.dup_addr = ns_socket_dup_addr,
|
||||
.match_addr = ns_socket_match_addr,
|
||||
.update = ns_socket_update,
|
||||
.send = ns_socket_send,
|
||||
.shutdown = ns_socket_shutdown,
|
||||
.initialize = ns_socket_initialize,
|
||||
.get_id = ns_socket_get_id,
|
||||
.get_id_str = ns_socket_get_id_str,
|
||||
.save_id = ns_socket_save_id,
|
||||
.clear_id = ns_socket_clear_id,
|
||||
.dup_addr = ns_socket_dup_addr,
|
||||
.match_addr = ns_socket_match_addr,
|
||||
.update = ns_socket_update,
|
||||
.send = ns_socket_send,
|
||||
.get_lobby_id = ns_socket_get_lobby_id,
|
||||
.get_lobby_secret = ns_socket_get_lobby_secret,
|
||||
.shutdown = ns_socket_shutdown,
|
||||
.requireServerBroadcast = true,
|
||||
.name = "Socket",
|
||||
.name = "Socket",
|
||||
};
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include <stdio.h>
|
||||
#include "version.h"
|
||||
#include "version_text.h"
|
||||
#include "types.h"
|
||||
|
||||
static char sVersionString[MAX_VERSION_LENGTH] = { 0 };
|
||||
static char sLocalVersionString[MAX_LOCAL_VERSION_LENGTH] = { 0 };
|
||||
|
||||
char* get_version(void) {
|
||||
snprintf(sVersionString, MAX_VERSION_LENGTH, "%s %d.%d", VERSION_TEXT, VERSION_NUMBER, MINOR_VERSION_NUMBER);
|
||||
snprintf(sVersionString, MAX_VERSION_LENGTH, "%s", VERSION_TEXT);
|
||||
return sVersionString;
|
||||
}
|
||||
|
||||
|
@ -14,6 +15,6 @@ char* get_version_local(void) {
|
|||
if (PATCH_VERSION_NUMBER <= 0) {
|
||||
return get_version();
|
||||
}
|
||||
snprintf(sLocalVersionString, MAX_LOCAL_VERSION_LENGTH, "%s %d.%d.%d", VERSION_TEXT, VERSION_NUMBER, MINOR_VERSION_NUMBER, PATCH_VERSION_NUMBER);
|
||||
snprintf(sLocalVersionString, MAX_LOCAL_VERSION_LENGTH, "%s.%d", VERSION_TEXT, PATCH_VERSION_NUMBER);
|
||||
return sLocalVersionString;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define VERSION_TEXT "beta"
|
||||
#define VERSION_NUMBER 33
|
||||
#define MINOR_VERSION_NUMBER 1
|
||||
#define PATCH_VERSION_NUMBER 0
|
||||
|
||||
#define MAX_VERSION_LENGTH 10
|
||||
#define MAX_LOCAL_VERSION_LENGTH 12
|
||||
#define MAX_VERSION_LENGTH 28
|
||||
#define MAX_LOCAL_VERSION_LENGTH 32
|
||||
|
||||
char* get_version(void);
|
||||
char* get_version_local(void);
|
||||
|
||||
|
|
2
src/pc/network/version_text.h
Normal file
2
src/pc/network/version_text.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
#pragma once
|
||||
#define VERSION_TEXT "beta 34"
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue