diff --git a/libultraship/libultraship/Lib/SDL/SDL2/SDL_net.h b/libultraship/libultraship/Lib/SDL/SDL2/SDL_net.h new file mode 100644 index 000000000..efe49228b --- /dev/null +++ b/libultraship/libultraship/Lib/SDL/SDL2/SDL_net.h @@ -0,0 +1,1048 @@ +/* + SDL_net: An example cross-platform network library for use with SDL + Copyright (C) 1997-2022 Sam Lantinga + Copyright (C) 2012 Simeon Maxein + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_NET_H_ +#define SDL_NET_H_ + +#ifdef WITHOUT_SDL +#include +typedef uint8_t Uint8; +typedef uint16_t Uint16; +typedef uint32_t Uint32; + +typedef struct SDLNet_version { + Uint8 major; + Uint8 minor; + Uint8 patch; +} SDLNet_version; + +#else /* WITHOUT_SDL */ + +#if __APPLE__ +#include +#include "SDL_endian.h" +#include "SDL_version.h" +#else +#include +#include +#include +#endif + +typedef SDL_version SDLNet_version; + +#endif /* WITHOUT_SDL */ + +#include "begin_code.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL +*/ +#define SDL_NET_MAJOR_VERSION 2 +#define SDL_NET_MINOR_VERSION 1 +#define SDL_NET_PATCHLEVEL 0 + +/* This macro can be used to fill a version structure with the compile-time + * version of the SDL_net library. + */ +#define SDL_NET_VERSION(X) \ +{ \ + (X)->major = SDL_NET_MAJOR_VERSION; \ + (X)->minor = SDL_NET_MINOR_VERSION; \ + (X)->patch = SDL_NET_PATCHLEVEL; \ +} + +#if SDL_NET_MAJOR_VERSION < 3 && SDL_MAJOR_VERSION < 3 +/** + * This is the version number macro for the current SDL_net version. + * + * In versions higher than 2.9.0, the minor version overflows into + * the thousands digit: for example, 2.23.0 is encoded as 4300. + * This macro will not be available in SDL 3.x or SDL_net 3.x. + * + * Deprecated, use SDL_NET_VERSION_ATLEAST or SDL_NET_VERSION instead. + */ +#define SDL_NET_COMPILEDVERSION \ + SDL_VERSIONNUM(SDL_NET_MAJOR_VERSION, SDL_NET_MINOR_VERSION, SDL_NET_PATCHLEVEL) +#endif /* SDL_NET_MAJOR_VERSION < 3 && SDL_MAJOR_VERSION < 3 */ + +/** + * This macro will evaluate to true if compiled with SDL_net at least X.Y.Z. + */ +#define SDL_NET_VERSION_ATLEAST(X, Y, Z) \ + ((SDL_NET_MAJOR_VERSION >= X) && \ + (SDL_NET_MAJOR_VERSION > X || SDL_NET_MINOR_VERSION >= Y) && \ + (SDL_NET_MAJOR_VERSION > X || SDL_NET_MINOR_VERSION > Y || SDL_NET_PATCHLEVEL >= Z)) + +/** + * Query the version of SDL_net that the program is linked against. + * + * This function gets the version of the dynamically linked SDL_net library. + * This is separate from the SDL_NET_VERSION() macro, which tells you what + * version of the SDL_net headers you compiled against. + * + * This returns static internal data; do not free or modify it! + * + * \returns a pointer to the version information. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC const SDLNet_version * SDLCALL SDLNet_Linked_Version(void); + +/** + * Initialize SDL_net. + * + * You must successfully call this function before it is safe to call any + * other function in this library, with one exception: a human-readable error + * message can be retrieved from SDLNet_GetError() if this function fails. + * + * SDL must be initialized before calls to functions in this library, because + * this library uses utility functions from the SDL library. + * + * It is safe to call this more than once; the library keeps a counter of init + * calls, and decrements it on each call to SDLNet_Quit, so you must pair your + * init and quit calls. + * + * \returns 0 on success, -1 on error. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC int SDLCALL SDLNet_Init(void); + +/** + * Deinitialize SDL_net. + * + * You must call this when done with the library, to free internal resources. + * It is safe to call this when the library isn't initialized, as it will just + * return immediately. + * + * Once you have as many quit calls as you have had successful calls to + * SDLNet_Init, the library will actually deinitialize. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC void SDLCALL SDLNet_Quit(void); + + +/* IPv4 hostname resolution API... */ + +typedef struct { + Uint32 host; /* 32-bit IPv4 host address */ + Uint16 port; /* 16-bit protocol port */ +} IPaddress; + +#ifndef INADDR_ANY +#define INADDR_ANY 0x00000000 +#endif +#ifndef INADDR_NONE +#define INADDR_NONE 0xFFFFFFFF +#endif +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001 +#endif +#ifndef INADDR_BROADCAST +#define INADDR_BROADCAST 0xFFFFFFFF +#endif + +/** + * Resolve a host name and port to an IP address in network form. + * + * If `host` is NULL, the resolved host will be set to `INADDR_ANY`. + * + * If the host couldn't be resolved, the host portion of the returned address + * will be INADDR_NONE, and the function will return -1. + * + * \param address to be filled in with the resolved address and port. + * \param host the hostname to lookup (like "libsdl.org") + * \param port the port intended to be connected to, to fill into address. + * \returns zero on success, -1 on error. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC int SDLCALL SDLNet_ResolveHost(IPaddress *address, const char *host, Uint16 port); + +/** + * Resolve an IP address to a host name in canonical form. + * + * If the IP couldn't be resolved, this function returns NULL, otherwise a + * pointer to a static buffer containing the hostname is returned. + * + * **Warning**: This function is not thread-safe! + * + * \param ip the IP address to resolve into a hostname. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC const char * SDLCALL SDLNet_ResolveIP(const IPaddress *ip); + +/** + * Get the addresses of network interfaces on this system. + * + * \param addresses where to store the returned information. + * \param maxcount the number of results that can be stored at `addresses` + * \returns the number of addresses saved in `addresses` + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC int SDLCALL SDLNet_GetLocalAddresses(IPaddress *addresses, int maxcount); + + +/* TCP network API */ + +typedef struct _TCPsocket *TCPsocket; + +/** + * Open a TCP network socket. + * + * If `ip->host` is INADDR_NONE or INADDR_ANY, this creates a local server + * socket on the given port, otherwise a TCP connection to the remote host and + * port is attempted. The address passed in should already be swapped to + * network byte order (addresses returned from SDLNet_ResolveHost() are + * already in the correct form). + * + * \param ip The address to open a connection to (or to host a server on). + * \returns the newly created socket, or NULL if there was an error. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_TCP_Close + */ +extern DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Open(IPaddress *ip); + +/** + * Accept an incoming connection on the given server socket. + * + * `server` must be a socket returned by SDLNet_TCP_Open with an address of + * INADDR_NONE or INADDR_ANY (a "server socket"). Other sockets do not accept + * connections. + * + * \param server the server socket to accept a connection on. + * \returns the newly created socket, or NULL if there was an error. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Accept(TCPsocket server); + +/** + * Get the IP address of the remote system associated with the socket. + * + * If the socket is a server socket, this function returns NULL. + * + * This returns a pointer to internal memory; you should not modify or free + * it, and should assume it's only valid until the socket is given to + * SDLNet_TCP_Close. + * + * \param sock the socket to query. + * \returns the address information for the socket. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC IPaddress * SDLCALL SDLNet_TCP_GetPeerAddress(TCPsocket sock); + +/** + * Send data over a non-server socket. + * + * `sock` must be a valid socket that was created by SDLNet_TCP_Open with a + * specific address, or SDLNet_TCP_Accept. + * + * This function sends `len` bytes, pointed to by `data` over the non-server + * socket `sock`. + * + * This function returns the actual amount of data sent. If the return value + * is less than the amount of data sent, then either the remote connection was + * closed, or an unknown socket error occurred. + * + * This function may block! + * + * \param sock the socket to send data to. + * \param data a pointer to the bytes to send. + * \param len the number of bytes, pointed to by `data`, to transmit. + * \returns number of bytes sent, which might be less if there was a problem + * or connection failure. If the socket is invalid, this function can + * return -1, but in valid uses it'll return >= 0. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_TCP_Recv + */ +extern DECLSPEC int SDLCALL SDLNet_TCP_Send(TCPsocket sock, const void *data, int len); + +/** + * Receive data from a non-server socket. + * + * `sock` must be a valid socket that was created by SDLNet_TCP_Open with a + * specific address, or SDLNet_TCP_Accept. + * + * Receive up to `maxlen` bytes of data over the non-server socket `sock`, and + * store them in the buffer pointed to by `data`. + * + * This function returns the actual amount of data received. If the return + * value is less than or equal to zero, then either the remote connection was + * closed, or an unknown socket error occurred. + * + * Note that this will return the number of bytes available at the first + * moment the socket is able to see new data. If packets are coming in slowly + * from the network, this might be less data than you expect at a given time. + * + * This function may block! Use SDLNet_CheckSockets() to make sure there is + * data available before calling this function, if you want to avoid blocking. + * + * \param sock the socket to send data to. + * \param data a pointer to where to store received data. + * \param maxlen the maximum number of bytes that can be stored at `data`. + * \returns number of bytes received, which might be less than `maxlen`. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_TCP_Send + * \sa SDLNet_CheckSockets + */ +extern DECLSPEC int SDLCALL SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen); + +/** + * Close a TCP network socket. + * + * All TCP sockets (server and non-server) are deinitialized through this + * function. Call this once you are done with a socket, and assume the handle + * is invalid once you have. + * + * Closing a socket will disconnect any communication and free its resources. + * + * \param sock socket to close. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC void SDLCALL SDLNet_TCP_Close(TCPsocket sock); + + +/* UDP network API */ + +/* The maximum channels on a a UDP socket */ +#define SDLNET_MAX_UDPCHANNELS 32 +/* The maximum addresses bound to a single UDP socket channel */ +#define SDLNET_MAX_UDPADDRESSES 4 + +typedef struct _UDPsocket *UDPsocket; +typedef struct { + int channel; /* The src/dst channel of the packet */ + Uint8 *data; /* The packet data */ + int len; /* The length of the packet data */ + int maxlen; /* The size of the data buffer */ + int status; /* packet status after sending */ + IPaddress address; /* The source/dest address of an incoming/outgoing packet */ +} UDPpacket; + +/** + * Allocate a single UDP packet. + * + * This allocates a packet with `size` bytes of space for payload. + * + * When done with this packet, you can free it with SDLNet_FreePacket. Packets + * can be reused multiple times; you don't have to allocate a new one for each + * piece of data you intend to send. + * + * You can allocate multiple packets at once with SDLNet_AllocPacketV. + * + * \param size the maximum number of bytes of payload this packet will + * contain. + * \returns the new packet, or NULL if the function ran out of memory. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_ResizePacket + * \sa SDLNet_FreePacket + * \sa SDLNet_AllocPacketV + */ +extern DECLSPEC UDPpacket * SDLCALL SDLNet_AllocPacket(int size); + + +/** + * Reallocate a UDP packet's payload space. + * + * This takes an existing packet and makes sure it can contain at least + * `newsize` bytes of space for payload. + * + * When done with this packet, you can free it with SDLNet_FreePacket. Packets + * can be used multiple times; you don't have to allocate a new one for each + * piece of data you intend to send. + * + * Please note that on memory allocation failure, this function will leave the + * existing buffer alone, and _will return the original buffer size_. It will + * not return an error value, it'll just leave the packet as it was! + * + * **Warning**: Existing contents of the packet's data are lost when resizing, + * whether you are growing or shrinking the payload space, since SDL_net does + * not realloc the existing data. + * + * \param newsize the new maximum number of bytes of payload this packet will + * contain. + * \returns the new maximum payload size, which will be unchanged from the + * previous if the system ran out of memory. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_AllocPacket + * \sa SDLNet_FreePacket + */ +extern DECLSPEC int SDLCALL SDLNet_ResizePacket(UDPpacket *packet, int newsize); + + +/** + * Dispose of a UDP packet. + * + * This frees both the packet's payload and the packet itself. Once this call + * completes, the packet's pointer is invalid and should not be used anymore. + * + * \param packet the packet to free. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_AllocPacket + * \sa SDLNet_ResizePacket + */ +extern DECLSPEC void SDLCALL SDLNet_FreePacket(UDPpacket *packet); + +/** + * Allocate a UDP packet vector (array of packets). + * + * This allocates `howmany` packets at once, each `size` bytes long. + * + * You must free the results of this function with SDLNet_FreePacketV, and + * must not free individual packets from this function with SDLNet_FreePacket. + * + * \param howmany the number of packets to allocate. + * \param size the maximum bytes of payload each packet should contain. + * \returns a pointer to the first packet in the array, or NULL if the + * function ran out of memory. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_FreePacketV + */ +extern DECLSPEC UDPpacket ** SDLCALL SDLNet_AllocPacketV(int howmany, int size); + + +/** + * Free a UDP packet vector (array of packets). + * + * This frees the results of a previous call to SDLNet_AllocPacketV(), freeing + * both the set of packets and the array that holds them. + * + * It is safe to free a NULL array through here; it's a harmless no-op. + * + * You must not use this to free packets allocated through any function other + * than SDLNet_AllocPacketV(). + * + * \param packetV the results of a call to SDLNet_AllocPacketV(). + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_AllocPacketV + */ +extern DECLSPEC void SDLCALL SDLNet_FreePacketV(UDPpacket **packetV); + +/** + * Open a UDP network socket. + * + * If `port` is non-zero, the UDP socket is bound to a local port. + * + * The `port` should be given in native byte order, but is used internally in + * network (big endian) byte order, in addresses, etc. This allows other + * systems to send to this socket via a known port. + * + * Note that UDP sockets at the platform layer "bind" to a nework port number, + * but SDL_net's UDP sockets also "bind" to a "channel" on top of that, with + * SDLNet_UDP_Bind(). But the term is used for both. + * + * When you are done communicating over the returned socket, you can shut it + * down and free its resources with SDLNet_UDP_Close(). + * + * \param port the UDP port to bind this socket to. + * \returns a new UDP socket, ready to communicate. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_UDP_Close + * \sa SDLNet_UDP_Bind + */ +extern DECLSPEC UDPsocket SDLCALL SDLNet_UDP_Open(Uint16 port); + +/** + * Set the percentage of simulated packet loss for packets sent on the socket. + * + * SDL_net can optionally, at random, drop packets that are being sent and + * received, to simulate bad networking conditions. As these sort of + * conditions can happen in the real world but likely won't between machines + * on the same LAN, you can use this function in testing to make sure your app + * is robust against network problems even on a fast, reliable network. + * + * You probably don't want to use this function outside of local testing. + * + * \param sock the socket to simulate packet loss on. + * \param percent a value from 0 to 100 of likelihood to drop a packet (higher + * the number means more likelihood of dropping. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC void SDLCALL SDLNet_UDP_SetPacketLoss(UDPsocket sock, int percent); + +/** + * Bind an address to the requested channel on the UDP socket. + * + * Note that UDP sockets at the platform layer "bind" to a nework port number, + * but SDL_net's UDP sockets also "bind" to a "channel" on top of that, with + * SDLNet_UDP_Bind(). But the term is used for both. + * + * If `channel` is -1, then the first unbound channel that has not yet been + * bound to the maximum number of addresses will be bound with the given + * address as it's primary address. + * + * If the channel is already bound, this new address will be added to the list + * of valid source addresses for packets arriving on the channel. If the + * channel is not already bound, then the address becomes the primary address, + * to which all outbound packets on the channel are sent. + * + * \param sock the UDP socket to bind an address to a channel on. + * \param channel the channel of the socket to bind to, or -1 to use the first + * available channel. + * \param address the address to bind to the socket's channel. + * \returns the channel which was bound, or -1 on error. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_UDP_Unbind + */ +extern DECLSPEC int SDLCALL SDLNet_UDP_Bind(UDPsocket sock, int channel, const IPaddress *address); + +/** + * Unbind all addresses from the given channel. + * + * Note that UDP sockets at the platform layer "bind" to a nework port number, + * but SDL_net's UDP sockets also "bind" to a "channel" on top of that, with + * SDLNet_UDP_Bind(). But the term is used for both. + * + * \param sock the UDP socket to unbind addresses from a channel on. + * \param channel the channel of the socket to unbind. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_UDP_Bind + */ +extern DECLSPEC void SDLCALL SDLNet_UDP_Unbind(UDPsocket sock, int channel); + +/** + * Get the IP address of the remote system for a socket and channel. + * + * If `channel` is -1, then the primary IP port of the UDP socket is returned + * -- this is only meaningful for sockets opened with a specific port. + * + * If the channel is not bound and not -1, this function returns NULL. + * + * \param sock the UDP socket to unbind addresses from a channel on. + * \param channel the channel of the socket to unbind. + * \returns the address bound to the socket's channel, or + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC IPaddress * SDLCALL SDLNet_UDP_GetPeerAddress(UDPsocket sock, int channel); + +/** + * Send a vector of packets to the the channels specified within the packet. + * + * If the channel specified in the packet is -1, the packet will be sent to + * the address in the `src` member of the packet. + * + * Each packet will be updated with the status of the packet after it has been + * sent, -1 if the packet send failed. + * + * This function takes an array of packets but does not need to be allocated + * through SDLNet_AllocPacketV; if you supply your own array of packets you + * allocated individually, that is okay. + * + * **Warning**: UDP is an _unreliable protocol_, which means we can report + * that your packet has been successfully sent from your machine, but then it + * never makes it to its destination when a router along the way quietly drops + * it. If this happens--and this is a common result on the internet!--you will + * not know the packet never made it. Also, packets may arrive in a different + * order than you sent them. Plan accordingly! + * + * **Warning**: The maximum size of the packet is limited by the MTU (Maximum + * Transfer Unit) of the transport medium. It can be as low as 250 bytes for + * some PPP links, and as high as 1500 bytes for ethernet. Different sizes can + * be sent, but the system might split it into multiple transmission fragments + * behind the scenes, that need to be reassembled on the other side (and the + * packet is lost if any fragment is lost in transit). So the less you can + * reasonably send in a single packet, the better, as it will be more reliable + * and lower latency. + * + * \param sock the UDP socket to send packets on. + * \param packets an array of packets to send to the network. + * \param npackets the number of packets in the `packets` array. + * \returns the number of packets successfully sent from this machine. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_UDP_RecV + */ +extern DECLSPEC int SDLCALL SDLNet_UDP_SendV(UDPsocket sock, UDPpacket **packets, int npackets); + +/** + * Send a single UDP packet to the specified channel. + * + * If the channel specified is -1, the packet will be sent to the address in + * the `src` member of the packet. + * + * The packet will be updated with the status of the packet after it has been + * sent. + * + * **Warning**: UDP is an _unreliable protocol_, which means we can report + * that your packet has been successfully sent from your machine, but then it + * never makes it to its destination when a router along the way quietly drops + * it. If this happens--and this is a common result on the internet!--you will + * not know the packet never made it. Also, packets may arrive in a different + * order than you sent them. Plan accordingly! + * + * **Warning**: The maximum size of the packet is limited by the MTU (Maximum + * Transfer Unit) of the transport medium. It can be as low as 250 bytes for + * some PPP links, and as high as 1500 bytes for ethernet. Different sizes can + * be sent, but the system might split it into multiple transmission fragments + * behind the scenes, that need to be reassembled on the other side (and the + * packet is lost if any fragment is lost in transit). So the less you can + * reasonably send in a single packet, the better, as it will be more reliable + * and lower latency. + * + * \param sock the UDP socket to send packets on. + * \param packet a single packet to send to the network. + * \returns 1 if the packet was sent, or 0 on error. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC int SDLCALL SDLNet_UDP_Send(UDPsocket sock, int channel, UDPpacket *packet); + +/** + * Receive a vector of pending packets from a UDP socket. + * + * The returned packets contain the source address and the channel they + * arrived on. If they did not arrive on a bound channel, the the channel will + * be set to -1. + * + * The channels are checked in highest to lowest order, so if an address is + * bound to multiple channels, the highest channel with the source address + * bound will be returned. + * + * This function takes an array of packets but does not need to be allocated + * through SDLNet_AllocPacketV; if you supply your own array of packets you + * allocated individually, that is okay, as long as the last element in the + * array is NULL, so SDL_net knows the array bounds. The arrays returned by + * SDLNet_AllocPacketV are properly NULL-terminated for these purposes. + * + * This function does not block, so it can return 0 packets pending, which is + * not an error condition. + * + * \param sock the UDP socket to receive packets on. + * \param packets an array of packets, NULL terminated. + * \returns the number of packets read from the network, or -1 on error. 0 + * means no packets were currently available. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_UDP_SendV + * \sa SDLNet_UDP_Recv + */ +extern DECLSPEC int SDLCALL SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets); + +/** + * Receive a single packet from a UDP socket. + * + * The returned packets contain the source address and the channel they + * arrived on. If they did not arrive on a bound channel, the the channel will + * be set to -1. + * + * The channels are checked in highest to lowest order, so if an address is + * bound to multiple channels, the highest channel with the source address + * bound will be returned. + * + * This function does not block, so it can return 0 packets pending, which is + * not an error condition. + * + * \param sock the UDP socket to receive packets on. + * \param packet a single packet to receive data into from the network. + * \returns 1 if a new packet is available, or -1 on error. 0 means no packets + * were currently available. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_UDP_Send + * \sa SDLNet_UDP_RecvV + */ +extern DECLSPEC int SDLCALL SDLNet_UDP_Recv(UDPsocket sock, UDPpacket *packet); + +/** + * Close a UDP socket. + * + * This disconnects the socket and frees any resources it retains. + * + * This socket may not be used again once given to this function. + * + * \param sock UDP socket to close. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC void SDLCALL SDLNet_UDP_Close(UDPsocket sock); + + +/***********************************************************************/ +/* Hooks for checking sockets for available data */ +/***********************************************************************/ + +typedef struct _SDLNet_SocketSet *SDLNet_SocketSet; + +/* Any network socket can be safely cast to this socket type */ +typedef struct _SDLNet_GenericSocket { + int ready; +} *SDLNet_GenericSocket; + +/** + * Allocate a socket set for use with SDLNet_CheckSockets(). + * + * To query if new data is available on a socket, you use a "socket set" with + * SDLNet_CheckSockets(). A socket set is just a list of sockets behind the + * scenes; you allocate a set and then add/remove individual sockets to/from + * the set. + * + * When done with a socket set, you can free it with SDLNet_FreeSocketSet. + * + * \param maxsockets the maximum amount of sockets to include in this set. + * \returns a socket set for up to `maxsockets` sockets, or NULL if the + * function ran out of memory. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_FreeSocketSet + */ +extern DECLSPEC SDLNet_SocketSet SDLCALL SDLNet_AllocSocketSet(int maxsockets); + +/** + * Add a socket to a socket set, to be checked for available data. + * + * Generally you don't want to call this generic function, but rather the + * specific, inline function that wraps it: SDLNet_TCP_AddSocket() or + * SDLNet_UDP_AddSocket(). + * + * This function will fail if you add a socket to the set when the set already + * has its maximum number of sockets added, but otherwise it will always + * succeed. + * + * If `sock` is NULL, nothing is added to the set; this lets you query the + * number of sockets currently contained in the set. + * + * \param set the socket set to add a new socket to. + * \param sock the socket to add to the set. + * \returns the total number of sockets contained in the set (including this + * new one), or -1 if the set is already full. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_TCP_AddSocket + * \sa SDLNet_UDP_AddSocket + * \sa SDLNet_DelSocket + * \sa SDLNet_TCP_DelSocket + * \sa SDLNet_UDP_DelSocket + * \sa SDLNet_CheckSockets + */ +extern DECLSPEC int SDLCALL SDLNet_AddSocket(SDLNet_SocketSet set, SDLNet_GenericSocket sock); + +/** + * Add a TCP socket to a socket set, to be checked for available data. + * + * This is a small TCP-specific wrapper over SDLNet_AddSocket; please refer + * to that function's documentation. + * + * \param set the socket set to add a new socket to. + * \param sock the socket to add to the set. + * \returns the total number of sockets contained in the set (including this new one), + * or -1 if the set is already full. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_AddSocket + */ +SDL_FORCE_INLINE int SDLNet_TCP_AddSocket(SDLNet_SocketSet set, TCPsocket sock) +{ + return SDLNet_AddSocket(set, (SDLNet_GenericSocket)sock); +} + +/** + * Add a UDP socket to a socket set, to be checked for available data. + * + * This is a small UDP-specific wrapper over SDLNet_AddSocket; please refer + * to that function's documentation. + * + * \param set the socket set to add a new socket to. + * \param sock the socket to add to the set. + * \returns the total number of sockets contained in the set (including this new one), + * or -1 if the set is already full. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_AddSocket + */ +SDL_FORCE_INLINE int SDLNet_UDP_AddSocket(SDLNet_SocketSet set, UDPsocket sock) +{ + return SDLNet_AddSocket(set, (SDLNet_GenericSocket)sock); +} + + +/** + * Remove a socket from a set of sockets to be checked for available data. + * + * Generally you don't want to call this generic function, but rather the + * specific, inline function that wraps it: SDLNet_TCP_DelSocket() or + * SDLNet_UDP_DelSocket(). + * + * If `sock` is NULL, nothing is removed from the set; this lets you query the + * number of sockets currently contained in the set. + * + * This will return -1 if the socket was not found in the set; in such a case, + * nothing is removed from the set. + * + * \param set the socket set to remove a socket from. + * \param sock the socket to remove from the set. + * \returns the total number of sockets contained in the set (after `sock`'s + * removal), or -1 if `sock` was not in the set. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_TCP_DelSocket + * \sa SDLNet_UDP_DelSocket + * \sa SDLNet_AddSocket + * \sa SDLNet_TCP_AddSocket + * \sa SDLNet_UDP_AddSocket + * \sa SDLNet_CheckSockets + */ +extern DECLSPEC int SDLCALL SDLNet_DelSocket(SDLNet_SocketSet set, SDLNet_GenericSocket sock); + +/** + * Remove a TCP socket from a socket set. + * + * This is a small TCP-specific wrapper over SDLNet_DelSocket; please refer + * to that function's documentation. + * + * \param set the socket set to remove a socket from. + * \param sock the socket to remove from the set. + * \returns the total number of sockets contained in the set (after + * `sock`'s removal), or -1 if `sock` was not in the set. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_DelSocket + */ +SDL_FORCE_INLINE int SDLNet_TCP_DelSocket(SDLNet_SocketSet set, TCPsocket sock) +{ + return SDLNet_DelSocket(set, (SDLNet_GenericSocket)sock); +} + +/** + * Remove a UDP socket from a socket set. + * + * This is a small UDP-specific wrapper over SDLNet_DelSocket; please refer + * to that function's documentation. + * + * \param set the socket set to remove a socket from. + * \param sock the socket to remove from the set. + * \returns the total number of sockets contained in the set (after + * `sock`'s removal), or -1 if `sock` was not in the set. + * + * \since This function is available since SDL_net 2.0.0. + * + * \sa SDLNet_DelSocket + */ +SDL_FORCE_INLINE int SDLNet_UDP_DelSocket(SDLNet_SocketSet set, UDPsocket sock) +{ + return SDLNet_DelSocket(set, (SDLNet_GenericSocket)sock); +} + +/** + * Check a socket set for data availability. + * + * This function checks to see if data is available for reading on the given + * set of sockets. If 'timeout' is 0, it performs a quick poll, otherwise the + * function returns when either data is available for reading, or the timeout + * in milliseconds has elapsed, whichever occurs first. + * + * \param set the socket set to check for ready sockets. + * \param timeout the time to wait in milliseconds for new data to arrive. A + * timeout of zero checks for new data and returns without + * blocking. + * \returns the number of sockets ready for reading, or -1 if there was an + * error with the select() system call. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC int SDLCALL SDLNet_CheckSockets(SDLNet_SocketSet set, Uint32 timeout); + +/* !!! FIXME: wikiheaders.pl ignores macros, atm */ +/** + * See if a specific socket has data available after checking it in a set. + * + * After calling SDLNet_CheckSockets(), you can use this function on a + * socket that was in the socket set, to find out if data is available + * for reading. + * + * \param sock the socket to check. + * \returns non-zero if socket has new data available, zero otherwise. + * + * \since This function is available since SDL_net 2.0.0. + */ +#define SDLNet_SocketReady(sock) _SDLNet_SocketReady((SDLNet_GenericSocket)(sock)) +SDL_FORCE_INLINE int _SDLNet_SocketReady(SDLNet_GenericSocket sock) +{ + return (sock != NULL) && (sock->ready); +} + +/** + * Free a set of sockets allocated by SDLNet_AllocSocketSet(). + * + * When done with a socket set, call this function to free its resources. + * + * This only frees the socket set, not the individual sockets in the set, + * which would still (at some future point) need to be closed with + * SDLNet_TCP_Close or SDLNet_UDP_Close. + * + * \param set the socket set to free. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC void SDLCALL SDLNet_FreeSocketSet(SDLNet_SocketSet set); + + +/* Error reporting functions */ + +/** + * Set an error message to be retrieved with SDLNet_GetError. + * + * Generally you don't need to call this (SDL_net will use it internally to + * report errors), but it could be useful if you need to inject an error + * message of your own in here. + * + * \param fmt a printf-style format string for the error message. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC void SDLCALL SDLNet_SetError(const char *fmt, ...); + +/** + * Get the latest error message from SDL_net. + * + * The error message, depending on how SDL_net was built, may or may not be + * thread-local data. Sometimes things will set an error message when no + * failure was reported; the error string is only meaningful right after a + * public API reports a failure, and should be ignored otherwise. + * + * \returns the last set error message in UTF-8 encoding. + * + * \since This function is available since SDL_net 2.0.0. + */ +extern DECLSPEC const char * SDLCALL SDLNet_GetError(void); + +/* Inline functions to read/write network data */ + +/* Warning, most systems have data access alignment restrictions */ +#if defined(__i386__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64) +#define SDL_DATA_ALIGNED 0 +#endif +#ifndef SDL_DATA_ALIGNED +#define SDL_DATA_ALIGNED 1 +#endif + +/* Write a 16/32-bit value to network packet buffer */ +#define SDLNet_Write16(value, areap) _SDLNet_Write16(value, areap) +#define SDLNet_Write32(value, areap) _SDLNet_Write32(value, areap) + +/* Read a 16/32-bit value from network packet buffer */ +#define SDLNet_Read16(areap) _SDLNet_Read16(areap) +#define SDLNet_Read32(areap) _SDLNet_Read32(areap) + +#if !defined(WITHOUT_SDL) && !SDL_DATA_ALIGNED + +SDL_FORCE_INLINE void _SDLNet_Write16(Uint16 value, void *areap) +{ + *(Uint16 *)areap = SDL_SwapBE16(value); +} + +SDL_FORCE_INLINE void _SDLNet_Write32(Uint32 value, void *areap) +{ + *(Uint32 *)areap = SDL_SwapBE32(value); +} + +SDL_FORCE_INLINE Uint16 _SDLNet_Read16(const void *areap) +{ + return SDL_SwapBE16(*(const Uint16 *)areap); +} + +SDL_FORCE_INLINE Uint32 _SDLNet_Read32(const void *areap) +{ + return SDL_SwapBE32(*(const Uint32 *)areap); +} + +#else /* !defined(WITHOUT_SDL) && !SDL_DATA_ALIGNED */ + +SDL_FORCE_INLINE void _SDLNet_Write16(Uint16 value, void *areap) +{ + Uint8 *area = (Uint8*)areap; + area[0] = (value >> 8) & 0xFF; + area[1] = value & 0xFF; +} + +SDL_FORCE_INLINE void _SDLNet_Write32(Uint32 value, void *areap) +{ + Uint8 *area = (Uint8*)areap; + area[0] = (value >> 24) & 0xFF; + area[1] = (value >> 16) & 0xFF; + area[2] = (value >> 8) & 0xFF; + area[3] = value & 0xFF; +} + +SDL_FORCE_INLINE Uint16 _SDLNet_Read16(const void *areap) +{ + const Uint8 *area = (const Uint8*)areap; + return ((Uint16)area[0]) << 8 | ((Uint16)area[1]); +} + +SDL_FORCE_INLINE Uint32 _SDLNet_Read32(const void *areap) +{ + const Uint8 *area = (const Uint8*)areap; + return ((Uint32)area[0]) << 24 | ((Uint32)area[1]) << 16 | ((Uint32)area[2]) << 8 | ((Uint32)area[3]); +} + +#endif /* !defined(WITHOUT_SDL) && !SDL_DATA_ALIGNED */ + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* SDL_NET_H_ */ diff --git a/libultraship/libultraship/Lib/SDL/SDL2/SDLnetsys.h b/libultraship/libultraship/Lib/SDL/SDL2/SDLnetsys.h new file mode 100644 index 000000000..6f6dfaeaa --- /dev/null +++ b/libultraship/libultraship/Lib/SDL/SDL2/SDLnetsys.h @@ -0,0 +1,93 @@ +/* + SDL_net: An example cross-platform network library for use with SDL + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* $Id$ */ + +/* Include normal system headers */ +#include +#include +#include +#include + +#ifndef _WIN32_WCE +#include +#endif + +/* Include system network headers */ +#if defined(__WIN32__) || defined(WIN32) +#define __USE_W32_SOCKETS +#ifdef _WIN64 +#include +#include +#else +#include +/* NOTE: windows socklen_t is signed + * and is defined only for winsock2. */ +typedef int socklen_t; +#endif /* W64 */ +#include +#else /* UNIX */ +#include +#ifdef __FreeBSD__ +#include +#endif +#include +#include +#include +#include +#include +#ifndef __BEOS__ +#include +#endif +#include +#include +#include +#include +#endif /* WIN32 */ + +/* FIXME: What platforms need this? */ +#if 0 +typedef Uint32 socklen_t; +#endif + +/* System-dependent definitions */ +#ifndef __USE_W32_SOCKETS +#ifdef __OS2__ +#define closesocket soclose +#else /* !__OS2__ */ +#define closesocket close +#endif /* __OS2__ */ +#define SOCKET int +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +#endif /* __USE_W32_SOCKETS */ + +#ifdef __USE_W32_SOCKETS +#define SDLNet_GetLastError WSAGetLastError +#define SDLNet_SetLastError WSASetLastError +#ifndef EINTR +#define EINTR WSAEINTR +#endif +#else +int SDLNet_GetLastError(void); +void SDLNet_SetLastError(int err); +#endif + diff --git a/libultraship/libultraship/Lib/SDL/SDL2/chat.h b/libultraship/libultraship/Lib/SDL/SDL2/chat.h new file mode 100644 index 000000000..316e04201 --- /dev/null +++ b/libultraship/libultraship/Lib/SDL/SDL2/chat.h @@ -0,0 +1,53 @@ +/* + CHAT: A chat client/server using the SDL example network library + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* $Id$ */ + +/* Convert four letters into a number */ +#define MAKE_NUM(A, B, C, D) (((A+B)<<8)|(C+D)) + +/* Defines for the chat client */ +#define CHAT_SCROLLBACK 512 /* Save 512 lines in scrollback */ +#define CHAT_PROMPT "> " +#define CHAT_PACKETSIZE 256 /* Maximum length of a message */ + +/* Defines shared between the server and client */ +#define CHAT_PORT MAKE_NUM('C','H','A','T') + +/* The protocol between the chat client and server */ +#define CHAT_HELLO 0 /* 0+Port+len+name */ +#define CHAT_HELLO_PORT 1 +#define CHAT_HELLO_NLEN CHAT_HELLO_PORT+2 +#define CHAT_HELLO_NAME CHAT_HELLO_NLEN+1 +#define CHAT_ADD 1 /* 1+N+IP+Port+len+name */ +#define CHAT_ADD_SLOT 1 +#define CHAT_ADD_HOST CHAT_ADD_SLOT+1 +#define CHAT_ADD_PORT CHAT_ADD_HOST+4 +#define CHAT_ADD_NLEN CHAT_ADD_PORT+2 +#define CHAT_ADD_NAME CHAT_ADD_NLEN+1 +#define CHAT_DEL 2 /* 2+N */ +#define CHAT_DEL_SLOT 1 +#define CHAT_DEL_LEN CHAT_DEL_SLOT+1 +#define CHAT_BYE 255 /* 255 */ +#define CHAT_BYE_LEN 1 + +/* The maximum number of people who can talk at once */ +#define CHAT_MAXPEOPLE 10 diff --git a/libultraship/libultraship/Lib/SDL/lib/x64/SDL2_net_debug_x64.lib b/libultraship/libultraship/Lib/SDL/lib/x64/SDL2_net_debug_x64.lib new file mode 100644 index 000000000..5bb5fa2b3 Binary files /dev/null and b/libultraship/libultraship/Lib/SDL/lib/x64/SDL2_net_debug_x64.lib differ diff --git a/libultraship/libultraship/Lib/SDL/lib/x64/SDL2_net_release_x64.lib b/libultraship/libultraship/Lib/SDL/lib/x64/SDL2_net_release_x64.lib new file mode 100644 index 000000000..947752bd6 Binary files /dev/null and b/libultraship/libultraship/Lib/SDL/lib/x64/SDL2_net_release_x64.lib differ diff --git a/libultraship/libultraship/Lib/SDL/lib/x86/SDL2.lib b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2.lib index 56cfeb65c..45b882315 100644 Binary files a/libultraship/libultraship/Lib/SDL/lib/x86/SDL2.lib and b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2.lib differ diff --git a/libultraship/libultraship/Lib/SDL/lib/x86/SDL2_net_debug_x86.lib b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2_net_debug_x86.lib new file mode 100644 index 000000000..20afe9877 Binary files /dev/null and b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2_net_debug_x86.lib differ diff --git a/libultraship/libultraship/Lib/SDL/lib/x86/SDL2_net_release_x86.lib b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2_net_release_x86.lib new file mode 100644 index 000000000..23d4d0c0a Binary files /dev/null and b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2_net_release_x86.lib differ diff --git a/libultraship/libultraship/Lib/SDL/lib/x86/SDL2main.lib b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2main.lib index c54e25144..0c745423b 100644 Binary files a/libultraship/libultraship/Lib/SDL/lib/x86/SDL2main.lib and b/libultraship/libultraship/Lib/SDL/lib/x86/SDL2main.lib differ diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 5342374f0..4da6da571 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -222,6 +222,13 @@ set(Header_Files__soh__Enhancements__custom_message source_group("Header Files\\soh\\Enhancements\\custom-message" FILES ${Header_Files__soh__Enhancements__custom_message}) +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") +set(Header_Files__soh__Enhancements__crowd_control + "soh/Enhancements/crowd-control/CrowdControl.h" +) +source_group("Header Files\\soh\\Enhancements\\crowd-control" FILES ${Header_Files__soh__Enhancements__crowd_control}) +endif() + set(Source_Files__soh "soh/GbiWrap.cpp" "soh/OTRAudio.h" @@ -339,6 +346,13 @@ set(Source_Files__soh__Enhancements__custom_message source_group("Source Files\\soh\\Enhancements\\custom-message" FILES ${Source_Files__soh__Enhancements__custom_message}) +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") +set(Source_Files__soh__Enhancements__crowd_control + "soh/Enhancements/crowd-control/CrowdControl.cpp" +) +source_group("Source Files\\soh\\Enhancements\\crowd-control" FILES ${Source_Files__soh__Enhancements__crowd_control}) +endif() + set(Source_Files__src__boot "src/boot/assert.c" "src/boot/boot_main.c" @@ -1548,6 +1562,7 @@ set(ALL_FILES ${Header_Files__soh__Enhancements__randomizer} ${Header_Files__soh__Enhancements__randomizer__3drando} ${Header_Files__soh__Enhancements__custom_message} + ${Header_Files__soh__Enhancements__crowd_control} ${Source_Files__soh} ${Source_Files__soh__Enhancements} ${Source_Files__soh__Enhancements__cosmetics} @@ -1557,6 +1572,7 @@ set(ALL_FILES ${Source_Files__soh__Enhancements__randomizer__3drando__hint_list} ${Source_Files__soh__Enhancements__randomizer__3drando__location_access} ${Source_Files__soh__Enhancements__custom_message} + ${Source_Files__soh__Enhancements__crowd_control} ${Source_Files__src__boot} ${Source_Files__src__buffers} ${Source_Files__src__code} @@ -1663,7 +1679,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") "$<$:" "_DEBUG;" "_CRT_SECURE_NO_WARNINGS;" - "ENABLE_DX11" + "ENABLE_DX11;" + "ENABLE_CROWD_CONTROL" ">" "$<$:" "NDEBUG" diff --git a/soh/include/tables/actor_table.h b/soh/include/tables/actor_table.h index cdbebbc63..28ed9b67d 100644 --- a/soh/include/tables/actor_table.h +++ b/soh/include/tables/actor_table.h @@ -481,3 +481,6 @@ /* 0x01D4 */ DEFINE_ACTOR(En_Mm2, ACTOR_EN_MM2, ALLOCTYPE_NORMAL) /* 0x01D5 */ DEFINE_ACTOR(Bg_Jya_Block, ACTOR_BG_JYA_BLOCK, ALLOCTYPE_NORMAL) /* 0x01D6 */ DEFINE_ACTOR(Obj_Warp2block, ACTOR_OBJ_WARP2BLOCK, ALLOCTYPE_NORMAL) +#ifdef __ENABLE_CROWD_CONTROL__ +/* 0x01D7 */ DEFINE_ACTOR(Obj_CrowdControl, ACTOR_CROWD_CONTROL, ALLOCTYPE_NORMAL) +#endif diff --git a/soh/soh/Enhancements/crowd-control/CrowdControl.cpp b/soh/soh/Enhancements/crowd-control/CrowdControl.cpp new file mode 100644 index 000000000..d8ba57272 --- /dev/null +++ b/soh/soh/Enhancements/crowd-control/CrowdControl.cpp @@ -0,0 +1,217 @@ +#ifdef ENABLE_CROWD_CONTROL + +#include "CrowdControl.h" +#include "Cvar.h" +#include "Lib/json.hpp" +#include +#include + +#include "soh/Enhancements/debugconsole.h" + +extern "C" u8 ExecuteEffect(const char* effectId, uint32_t value); +extern "C" void RemoveEffect(const char* effectId); + +namespace Ship { + namespace CrowdControl { + void CrowdControl::InitCrowdControl() { + SDLNet_Init(); + + if (SDLNet_ResolveHost(&ip, "127.0.0.1", 43384) == -1) { + printf("SDLNet_ResolveHost: %s\n", SDLNet_GetError()); + } + + ccThreadReceive = std::thread(&CrowdControl::ReceiveFromCrowdControl, this); + } + + void CrowdControl::RunCrowdControl(CCPacket* packet) { + u8 paused = 0; + + while (connected) { + u8 anotherEffect = 0; + + nlohmann::json dataSend; + + dataSend["id"] = packet->packetId; + dataSend["type"] = 0; + + dataSend["timeRemaining"] = packet->timeRemaining; + + for (CCPacket* pack : receivedCommands) { + if (pack != packet && pack->effectCategory == packet->effectCategory && pack->packetId < packet->packetId) { + anotherEffect = 1; + dataSend["status"] = EffectResult::Retry; + break; + } + } + + u8 returnSuccess = 0; + if (anotherEffect == 0) { + returnSuccess = ExecuteEffect(packet->effectType.c_str(), packet->effectValue); + dataSend["status"] = returnSuccess == 1 ? EffectResult::Success : returnSuccess == 2 ? EffectResult::Failure : EffectResult::Retry; + } + + std::string jsonResponse = dataSend.dump(); + SDLNet_TCP_Send(tcpsock, const_cast (jsonResponse.data()), jsonResponse.size() + 1); + + if (anotherEffect == 0) { + if (returnSuccess == 2) { + return; + } + + if (returnSuccess == 1) { + if (paused && packet->timeRemaining > 0) { + paused = 0; + nlohmann::json dataSend; + dataSend["id"] = packet->packetId; + dataSend["type"] = 0; + dataSend["timeRemaining"] = packet->timeRemaining; + dataSend["status"] = EffectResult::Resumed; + + std::string jsonResponse = dataSend.dump(); + SDLNet_TCP_Send(tcpsock, const_cast (jsonResponse.data()), jsonResponse.size() + 1); + } + + if (packet->timeRemaining <= 0) { + receivedCommands.erase(std::remove(receivedCommands.begin(), receivedCommands.end(), packet), receivedCommands.end()); + RemoveEffect(packet->effectType.c_str()); + return; + } + + packet->timeRemaining -= 1000; + + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + else if (returnSuccess == 0 && paused == 0 && packet->timeRemaining > 0) { + paused = 1; + + nlohmann::json dataSend; + dataSend["id"] = packet->packetId; + dataSend["type"] = 0; + dataSend["timeRemaining"] = packet->timeRemaining; + dataSend["status"] = EffectResult::Paused; + + std::string jsonResponse = dataSend.dump(); + SDLNet_TCP_Send(tcpsock, const_cast (jsonResponse.data()), jsonResponse.size() + 1); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + else { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + else { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + + void CrowdControl::ReceiveFromCrowdControl() + { + printf("Waiting for a connection from Crowd Control..."); + + while (!connected && CVar_GetS32("gCrowdControl", 0) == 1) { + tcpsock = SDLNet_TCP_Open(&ip); + + if (tcpsock) { + connected = true; + printf("Connected to Crowd Control!"); + break; + } + } + + while (connected && CVar_GetS32("gCrowdControl", 0) == 1 && tcpsock) { + int len = SDLNet_TCP_Recv(tcpsock, &received, 512); + + if (!len || !tcpsock || len == -1) { + printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError()); + break; + } + + nlohmann::json dataReceived = nlohmann::json::parse(received); + + CCPacket* packet = new CCPacket(); + packet->packetId = dataReceived["id"]; + packet->effectValue = dataReceived["type"]; + packet->effectType = dataReceived["code"].get(); + + if (strcmp(packet->effectType.c_str(), "high_gravity") == 0 || + strcmp(packet->effectType.c_str(), "low_gravity") == 0) { + packet->effectCategory = "gravity"; + packet->timeRemaining = 30000; + } + else if (strcmp(packet->effectType.c_str(), "defense_modifier") == 0) { + packet->effectCategory = "defense"; + packet->timeRemaining = 30000; + } + else if (strcmp(packet->effectType.c_str(), "giant_link") == 0 || + strcmp(packet->effectType.c_str(), "minish_link") == 0 || + strcmp(packet->effectType.c_str(), "invisible") == 0 || + strcmp(packet->effectType.c_str(), "paper_link") == 0) { + packet->effectCategory = "link_size"; + packet->timeRemaining = 30000; + } + else if (strcmp(packet->effectType.c_str(), "freeze") == 0 || + strcmp(packet->effectType.c_str(), "damage") == 0 || + strcmp(packet->effectType.c_str(), "heal") == 0 || + strcmp(packet->effectType.c_str(), "knockback") == 0 || + strcmp(packet->effectType.c_str(), "electrocute") == 0 || + strcmp(packet->effectType.c_str(), "burn") == 0) { + packet->effectCategory = "link_damage"; + } + else if (strcmp(packet->effectType.c_str(), "hover_boots") == 0 || + strcmp(packet->effectType.c_str(), "iron_boots") == 0) { + packet->effectCategory = "boots"; + packet->timeRemaining = 30000; + } + else if (strcmp(packet->effectType.c_str(), "add_heart_container") == 0 || + strcmp(packet->effectType.c_str(), "remove_heart_container") == 0) { + packet->effectCategory = "heart_container"; + } + else if (strcmp(packet->effectType.c_str(), "no_ui") == 0) { + packet->effectCategory = "ui"; + } + else if (strcmp(packet->effectType.c_str(), "fill_magic") == 0 || + strcmp(packet->effectType.c_str(), "empty_magic") == 0) { + packet->effectCategory = "magic"; + } + else if (strcmp(packet->effectType.c_str(), "ohko") == 0) { + packet->effectCategory = "ohko"; + } + else if (strcmp(packet->effectType.c_str(), "pacifist") == 0) { + packet->effectCategory = "pacifist"; + } + else if (strcmp(packet->effectType.c_str(), "rainstorm") == 0) { + packet->effectCategory = "weather"; + } + else if (strcmp(packet->effectType.c_str(), "reverse") == 0) { + packet->effectCategory = "controls"; + } + else if (strcmp(packet->effectType.c_str(), "rupees") == 0) { + packet->effectCategory = "rupees"; + } + else if (strcmp(packet->effectType.c_str(), "speed") == 0) { + packet->effectCategory = "speed"; + } + else if (strcmp(packet->effectType.c_str(), "wallmaster") == 0 || + strcmp(packet->effectType.c_str(), "cucco") == 0) { + packet->effectCategory = "spawn"; + } + else { + packet->effectCategory = "none"; + packet->timeRemaining = 0; + } + + receivedCommands.push_back(packet); + std::thread t = std::thread(&CrowdControl::RunCrowdControl, this, packet); + t.detach(); + } + + if (connected) { + SDLNet_TCP_Close(tcpsock); + SDLNet_Quit(); + connected = false; + } + } + } +} +#endif diff --git a/soh/soh/Enhancements/crowd-control/CrowdControl.h b/soh/soh/Enhancements/crowd-control/CrowdControl.h new file mode 100644 index 000000000..cc931d205 --- /dev/null +++ b/soh/soh/Enhancements/crowd-control/CrowdControl.h @@ -0,0 +1,89 @@ +#ifdef ENABLE_CROWD_CONTROL + +#ifndef _CROWDCONTROL_C +#define _CROWDCONTROL_C +#endif + +#include "stdint.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ship { + namespace CrowdControl { + typedef struct CCPacket { + uint32_t packetId; + std::string effectType; + uint32_t effectValue; + std::string effectCategory; + long timeRemaining; + } CCPacket; + + enum EffectResult { + /// The effect executed successfully. + Success = 0x00, + /// The effect failed to trigger, but is still available for use. Viewer(s) will be refunded. You probably don't want this. + Failure = 0x01, + /// Same as but the effect is no longer available for use for the remainder of the game. You probably don't want this. + Unavailable = 0x02, + /// The effect cannot be triggered right now, try again in a few seconds. This is the "normal" failure response. + Retry = 0x03, + /// INTERNAL USE ONLY. The effect has been queued for execution after the current one ends. + Queue = 0x04, + /// INTERNAL USE ONLY. The effect triggered successfully and is now active until it ends. + Running = 0x05, + /// The timed effect has been paused and is now waiting. + Paused = 0x06, + /// The timed effect has been resumed and is counting down again. + Resumed = 0x07, + /// The timed effect has finished. + Finished = 0x08, + /// The processor isn't ready to start or has shut down. + NotReady = 0xFF + }; + + enum ResponseType { + EffectRequest = 0x00, + Login = 0xF0, + LoginSuccess = 0xF1, + Disconnect = 0xFE, + KeepAlive = 0xFF + }; + + struct Response { + int id; + EffectResult status; + long timeRemaining; + ResponseType type = ResponseType::EffectRequest; + }; + + class CrowdControl { + private: + std::thread ccThreadReceive; + + TCPsocket tcpsock; + IPaddress ip; + + bool connected; + + char received[512]; + + std::vector currentCommands; + std::vector receivedCommands; + + void RunCrowdControl(CCPacket* packet); + void ReceiveFromCrowdControl(); + + public: + void InitCrowdControl(); + }; + } +} // namespace Ship +#endif diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 8e72392ca..9f6847d9c 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -33,6 +33,14 @@ extern GlobalContext* gGlobalCtx; #define CMD_REGISTER SohImGui::BindCmd +uint32_t defenseModifier; +uint32_t giantLink; +uint32_t minishLink; +uint32_t highGravity; +uint32_t resetLinkScale; +uint32_t noUi; +uint32_t invisibleLink; + static bool ActorSpawnHandler(std::shared_ptr Console, const std::vector& args) { if ((args.size() != 9) && (args.size() != 3) && (args.size() != 6)) { SohImGui::console->SendErrorMessage("Not enough arguments passed to actorspawn"); @@ -373,6 +381,25 @@ static bool StateSlotSelectHandler(std::shared_ptr Console, const return CMD_SUCCESS; } +static bool InvisibleHandler(std::shared_ptr Console, const std::vector& args) { + if (args.size() != 2) { + SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + + bool invisible; + + try { + invisible = std::stoi(args[1], nullptr, 10); + } catch (std::invalid_argument const& ex) { + SohImGui::console->SendErrorMessage("[SOH] Invisible value must be a number."); + return CMD_FAILED; + } + + invisibleLink = invisible; + return CMD_SUCCESS; +} + #define VARTYPE_INTEGER 0 #define VARTYPE_FLOAT 1 #define VARTYPE_STRING 2 @@ -466,47 +493,62 @@ void DebugConsole_Init(void) { CMD_REGISTER("rupee", { RuppeHandler, "Set your rupee counter.", { {"amount", Ship::ArgumentType::NUMBER } }}); - CMD_REGISTER("bItem", { BHandler, "Set an item to the B button.", { { "Item ID", Ship::ArgumentType::NUMBER } } }); - CMD_REGISTER("health", { SetPlayerHealthHandler, "Set the health of the player.", { { "health", Ship::ArgumentType::NUMBER } + CMD_REGISTER("bItem", { BHandler, "Set an item to the B button.", { + { "Item ID", Ship::ArgumentType::NUMBER } }}); - CMD_REGISTER("spawn", { ActorSpawnHandler, "Spawn an actor.", { { "actor_id", Ship::ArgumentType::NUMBER }, - { "data", Ship::ArgumentType::NUMBER }, - { "x", Ship::ArgumentType::PLAYER_POS, true }, - { "y", Ship::ArgumentType::PLAYER_POS, true }, - { "z", Ship::ArgumentType::PLAYER_POS, true }, - { "rx", Ship::ArgumentType::PLAYER_ROT, true }, - { "ry", Ship::ArgumentType::PLAYER_ROT, true }, - { "rz", Ship::ArgumentType::PLAYER_ROT, true } + CMD_REGISTER("health", { SetPlayerHealthHandler, "Set the health of the player.", { + { "health", Ship::ArgumentType::NUMBER } }}); - CMD_REGISTER("pos", { SetPosHandler, "Sets the position of the player.", { { "x", Ship::ArgumentType::PLAYER_POS, true }, - { "y", Ship::ArgumentType::PLAYER_POS, true }, - { "z", Ship::ArgumentType::PLAYER_POS, true } + CMD_REGISTER("spawn", { ActorSpawnHandler, "Spawn an actor.", { + { "actor_id", Ship::ArgumentType::NUMBER }, + { "data", Ship::ArgumentType::NUMBER }, + { "x", Ship::ArgumentType::PLAYER_POS, true }, + { "y", Ship::ArgumentType::PLAYER_POS, true }, + { "z", Ship::ArgumentType::PLAYER_POS, true }, + { "rx", Ship::ArgumentType::PLAYER_ROT, true }, + { "ry", Ship::ArgumentType::PLAYER_ROT, true }, + { "rz", Ship::ArgumentType::PLAYER_ROT, true } + }}); + CMD_REGISTER("pos", { SetPosHandler, "Sets the position of the player.", { + { "x", Ship::ArgumentType::PLAYER_POS, true }, + { "y", Ship::ArgumentType::PLAYER_POS, true }, + { "z", Ship::ArgumentType::PLAYER_POS, true } + }}); + CMD_REGISTER("set", { SetCVarHandler, "Sets a console variable.", { + { "varName", Ship::ArgumentType::TEXT }, + { "varValue", Ship::ArgumentType::TEXT } + }}); + CMD_REGISTER("get", { GetCVarHandler, "Gets a console variable.", { + { "varName", Ship::ArgumentType::TEXT } }}); - CMD_REGISTER("set", { SetCVarHandler, - "Sets a console variable.", - { { "varName", Ship::ArgumentType::TEXT }, { "varValue", Ship::ArgumentType::TEXT } } }); - CMD_REGISTER("get", { GetCVarHandler, "Gets a console variable.", { { "varName", Ship::ArgumentType::TEXT } } }); CMD_REGISTER("reset", { ResetHandler, "Resets the game." }); - CMD_REGISTER("ammo", { AmmoHandler, "Changes ammo of an item.", - { { "item", Ship::ArgumentType::TEXT }, { "count", Ship::ArgumentType::NUMBER } } }); + CMD_REGISTER("ammo", { AmmoHandler, "Changes ammo of an item.", { + { "item", Ship::ArgumentType::TEXT }, + { "count", Ship::ArgumentType::NUMBER } + }}); - CMD_REGISTER("bottle", { BottleHandler, - "Changes item in a bottle slot.", - { { "item", Ship::ArgumentType::TEXT }, { "slot", Ship::ArgumentType::NUMBER } } }); + CMD_REGISTER("bottle", { BottleHandler, "Changes item in a bottle slot.", { + { "item", Ship::ArgumentType::TEXT }, + { "slot", Ship::ArgumentType::NUMBER } + }}); - CMD_REGISTER("item", { ItemHandler, - "Sets item ID in arg 1 into slot arg 2. No boundary checks. Use with caution.", - { { "slot", Ship::ArgumentType::NUMBER }, { "item id", Ship::ArgumentType::NUMBER } } }); - CMD_REGISTER("entrance", { EntranceHandler, - "Sends player to the entered entrance (hex)", - { { "entrance", Ship::ArgumentType::NUMBER } } }); + CMD_REGISTER("item", { ItemHandler, "Sets item ID in arg 1 into slot arg 2. No boundary checks. Use with caution.", { + { "slot", Ship::ArgumentType::NUMBER }, + { "item id", Ship::ArgumentType::NUMBER } + }}); + CMD_REGISTER("entrance", { EntranceHandler, "Sends player to the entered entrance (hex)", { + { "entrance", Ship::ArgumentType::NUMBER } + }}); CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." }); CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." }); - CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", { { - "Slot number", - Ship::ArgumentType::NUMBER, - } - } }); + CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", { + { "Slot number", Ship::ArgumentType::NUMBER, } + }}); + + CMD_REGISTER("invisible", { InvisibleHandler, "Toggles invisibility.", { + { "invisible", Ship::ArgumentType::NUMBER } + }}); + CVar_Load(); } diff --git a/soh/soh/Enhancements/debugconsole.h b/soh/soh/Enhancements/debugconsole.h index ffd0cb0cb..22875dc43 100644 --- a/soh/soh/Enhancements/debugconsole.h +++ b/soh/soh/Enhancements/debugconsole.h @@ -1,3 +1,19 @@ #pragma once +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint32_t defenseModifier; +extern uint32_t giantLink; +extern uint32_t minishLink; +extern uint32_t highGravity; +extern uint32_t resetLinkScale; +extern uint32_t noUi; +extern uint32_t invisibleLink; +#ifdef __cplusplus +} +#endif + void DebugConsole_Init(void); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 104b7f1e4..991a6306a 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -4,8 +4,10 @@ #include #include "soh/Enhancements/gameconsole.h" +#include "soh/Enhancements/debugconsole.h" #include "../libultraship/ImGuiImpl.h" #include "soh/frame_interpolation.h" +#include #include @@ -1527,6 +1529,158 @@ void Gameplay_Main(GameState* thisx) { } +u8 PlayerGrounded(Player* player) { + return (player->actor.world.pos.y - player->actor.floorHeight) == 0; +} + +extern func_80AB70A0(EnNiw* this, GlobalContext* globalCtx); + +void RemoveEffect(const char* effectId) { + if (gGlobalCtx == NULL) { + return; + } + + Player* player = GET_PLAYER(gGlobalCtx); + + if (player != NULL) { + if (strcmp(effectId, "giant_link") == 0) { + giantLink = 0; + resetLinkScale = 1; + return; + } else if (strcmp(effectId, "minish_link") == 0) { + minishLink = 0; + resetLinkScale = 1; + } else if (strcmp(effectId, "defense_modifier") == 0) { + defenseModifier = 0; + return; + } else if (strcmp(effectId, "iron_boots") == 0 || strcmp(effectId, "hover_boots") == 0) { + player->currentBoots = PLAYER_BOOTS_KOKIRI; + Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_KOKIRI + 1); + Player_SetBootData(gGlobalCtx, player); + return; + } else if (strcmp(effectId, "high_gravity") == 0 || strcmp(effectId, "low_gravity") == 0) { + highGravity = 0; + return; + } else if (strcmp(effectId, "no_ui") == 0) { + noUi = 0; + return; + } else if (strcmp(effectId, "invisible") == 0) { + invisibleLink = 0; + player->actor.shape.shadowDraw = ActorShadow_DrawFeet; + return; + } + } +} + +u8 ExecuteEffect(const char* effectId, uint32_t value) { + if (gGlobalCtx == NULL) { + return 0; + } + + Player* player = GET_PLAYER(gGlobalCtx); + + if (player != NULL) { + if (strcmp(effectId, "add_heart_container") == 0) { + if (gSaveContext.healthCapacity >= 0x140) { + return 2; + } + gSaveContext.healthCapacity += 0x10; + return 1; + } else if (strcmp(effectId, "remove_heart_container") == 0) { + if ((gSaveContext.healthCapacity - 0x10) <= 0) { + return 2; + } + gSaveContext.healthCapacity -= 0x10; + return 1; + } + } + + if (player != NULL && !Player_InBlockingCsMode(gGlobalCtx, player) && gGlobalCtx->pauseCtx.state == 0) { + if (strcmp(effectId, "high_gravity") == 0) { + highGravity = 1; + return 1; + } else if (strcmp(effectId, "low_gravity") == 0) { + highGravity = 2; + return 1; + } else if (strcmp(effectId, "giant_link") == 0) { + giantLink = 1; + return 1; + } else if (strcmp(effectId, "minish_link") == 0) { + minishLink = 1; + return 1; + } else if (strcmp(effectId, "defense_modifier") == 0) { + defenseModifier = value; + return 1; + } else if (strcmp(effectId, "kill") == 0) { + if (PlayerGrounded(player)) { + gSaveContext.health = 0; + return 1; + } + return 0; + } else if (strcmp(effectId, "cucco") == 0) { + EnNiw* cucco = + (EnNiw*)Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_NIW, player->actor.world.pos.x, + player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, 0); + cucco->actionFunc = func_80AB70A0; + return 1; + } else if (strcmp(effectId, "damage") == 0) { + Health_ChangeBy(gGlobalCtx, -value * 16); + func_80837C0C(gGlobalCtx, player, 0, 0, 0, 0, 0); + player->invincibilityTimer = 28; + return 1; + } else if (strcmp(effectId, "heal") == 0) { + Health_ChangeBy(gGlobalCtx, value * 16); + return 1; + } else if (strcmp(effectId, "freeze") == 0) { + if (PlayerGrounded(player)) { + func_80837C0C(gGlobalCtx, player, 3, 0, 0, 0, 0); + return 1; + } + return 0; + } else if (strcmp(effectId, "knockback") == 0) { + func_8002F71C(gGlobalCtx, &player->actor, value * 5, player->actor.world.rot.y + 0x8000, value * 5); + return 1; + } else if (strcmp(effectId, "burn") == 0) { + if (PlayerGrounded(player)) { + for (int i = 0; i < 18; i++) { + player->flameTimers[i] = Rand_S16Offset(0, 200); + } + player->isBurning = true; + func_80837C0C(gGlobalCtx, player, 0, 0, 0, 0, 0); + return 1; + } + return 0; + } else if (strcmp(effectId, "electrocute") == 0) { + if (PlayerGrounded(player)) { + func_80837C0C(gGlobalCtx, player, 4, 0, 0, 0, 0); + return 1; + } + return 0; + } else if (strcmp(effectId, "iron_boots") == 0) { + player->currentBoots = PLAYER_BOOTS_IRON; + Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_IRON + 1); + Player_SetBootData(gGlobalCtx, player); + return 1; + } else if (strcmp(effectId, "hover_boots") == 0) { + player->currentBoots = PLAYER_BOOTS_HOVER; + Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_HOVER + 1); + Player_SetBootData(gGlobalCtx, player); + return 1; + } else if (strcmp(effectId, "wallmaster") == 0) { + Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_WALLMAS, player->actor.world.pos.x, player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, 0); + return 1; + } else if (strcmp(effectId, "no_ui") == 0) { + noUi = 1; + return 1; + } else if (strcmp(effectId, "invisible") == 0) { + invisibleLink = 1; + return 1; + } + } + + return 0; +} + // original name: "Game_play_demo_mode_check" s32 Gameplay_InCsMode(GlobalContext* globalCtx) { return (globalCtx->csCtx.state != CS_STATE_IDLE) || Player_InCsMode(globalCtx); diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index 2db533821..908ce82ca 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -5,6 +5,8 @@ #include "objects/object_triforce_spot/object_triforce_spot.h" #include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h" +#include "soh/Enhancements/debugconsole.h" + typedef struct { /* 0x00 */ u8 flag; /* 0x02 */ u16 textId; @@ -1037,6 +1039,11 @@ s32 func_80090014(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* p } } + if (invisibleLink) { + this->actor.shape.shadowDraw = NULL; + *dList = NULL; + } + return false; } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 1485d19fc..95015cd9f 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -21,6 +21,7 @@ #include "objects/object_link_child/object_link_child.h" #include "textures/icon_item_24_static/icon_item_24_static.h" #include +#include "soh/Enhancements/debugconsole.h" typedef struct { /* 0x00 */ u8 itemId; @@ -11105,6 +11106,35 @@ void Player_Update(Actor* thisx, GlobalContext* globalCtx) { MREG(53) = this->actor.world.pos.y; MREG(54) = this->actor.world.pos.z; MREG(55) = this->actor.world.rot.y; + + // Crowd Control + + if (giantLink == 1) { + this->actor.scale.x = 0.025f; + this->actor.scale.y = 0.025f; + this->actor.scale.z = 0.025f; + } + + if (minishLink == 1) { + this->actor.scale.x = 0.001f; + this->actor.scale.y = 0.001f; + this->actor.scale.z = 0.001f; + } + + if (resetLinkScale == 1) { + this->actor.scale.x = 0.01f; + this->actor.scale.y = 0.01f; + this->actor.scale.z = 0.01f; + resetLinkScale = 0; + } + + if (highGravity == 1) { + this->actor.gravity = -4.0f; + } + + if (highGravity == 2) { + this->actor.gravity = -0.3f; + } } static struct_80858AC8 D_80858AC8;