├── include ├── enet │ ├── lib │ │ ├── libenet.a │ │ └── libenet_32.a │ ├── utility.h │ ├── types.h │ ├── time.h │ ├── callbacks.h │ ├── list.h │ ├── unix.h │ ├── win32.h │ └── protocol.h ├── event_type │ ├── receive.hpp │ ├── connect.hpp │ ├── disconnect.hpp │ ├── disconnect.cpp │ ├── __event_type.hpp │ ├── __event_type.cpp │ ├── connect.cpp │ └── receive.cpp ├── commands │ ├── me.hpp │ ├── sb.hpp │ ├── edit.hpp │ ├── find.hpp │ ├── skin.hpp │ ├── warp.hpp │ ├── who.hpp │ ├── ghost.hpp │ ├── ageworld.hpp │ ├── __command.hpp │ ├── punch.hpp │ ├── weather.hpp │ ├── ghost.cpp │ ├── find.cpp │ ├── skin.cpp │ ├── punch.cpp │ ├── warp.cpp │ ├── who.cpp │ ├── me.cpp │ ├── ageworld.cpp │ ├── sb.cpp │ ├── edit.cpp │ ├── __command.cpp │ └── weather.cpp ├── state │ ├── movement.hpp │ ├── ping_reply.hpp │ ├── tile_change.hpp │ ├── item_activate.hpp │ ├── tile_activate.hpp │ ├── __states.hpp │ ├── item_activate_object.hpp │ ├── ping_reply.cpp │ ├── movement.cpp │ ├── __states.cpp │ ├── item_activate_object.cpp │ ├── item_activate.cpp │ └── tile_activate.cpp ├── action │ ├── dialog_return │ │ ├── popup.hpp │ │ ├── drop_item.hpp │ │ ├── find_item.hpp │ │ ├── lock_edit.hpp │ │ ├── megaphone.hpp │ │ ├── peer_edit.hpp │ │ ├── trash_item.hpp │ │ ├── create_blast.hpp │ │ ├── gateway_edit.hpp │ │ ├── socialportal.hpp │ │ ├── billboard_edit.hpp │ │ ├── __dialog_return.hpp │ │ ├── megaphone.cpp │ │ ├── find_item.cpp │ │ ├── lock_edit.cpp │ │ ├── trash_item.cpp │ │ ├── drop_item.cpp │ │ ├── create_blast.cpp │ │ ├── billboard_edit.cpp │ │ ├── peer_edit.cpp │ │ ├── gateway_edit.cpp │ │ ├── socialportal.cpp │ │ ├── __dialog_return.cpp │ │ └── popup.cpp │ ├── __action.hpp │ ├── buy.hpp │ ├── drop.hpp │ ├── info.hpp │ ├── input.hpp │ ├── quit.hpp │ ├── store.hpp │ ├── trash.hpp │ ├── wrench.hpp │ ├── friends.hpp │ ├── respawn.hpp │ ├── setSkin.hpp │ ├── enter_game.hpp │ ├── logging_in.hpp │ ├── dialog_return.hpp │ ├── itemfavourite.hpp │ ├── quit_to_exit.hpp │ ├── refresh_item_data.hpp │ ├── inventoryfavuitrigger.hpp │ ├── join_request.hpp │ ├── setSkin.cpp │ ├── refresh_item_data.cpp │ ├── quit.cpp │ ├── respawn.cpp │ ├── dialog_return.cpp │ ├── inventoryfavuitrigger.cpp │ ├── friends.cpp │ ├── itemfavourite.cpp │ ├── trash.cpp │ ├── drop.cpp │ ├── quit_to_exit.cpp │ ├── enter_game.cpp │ ├── info.cpp │ ├── logging_in.cpp │ ├── input.cpp │ ├── __action.cpp │ ├── wrench.cpp │ ├── store.cpp │ └── buy.cpp ├── on │ ├── SetBux.hpp │ ├── BillboardChange.hpp │ ├── SetClothing.hpp │ ├── NameChanged.hpp │ ├── Action.hpp │ ├── EmoticonDataChanged.hpp │ ├── RequestWorldSelectMenu.hpp │ ├── NameChanged.cpp │ ├── SetBux.cpp │ ├── Action.cpp │ ├── BillboardChange.cpp │ ├── SetClothing.cpp │ ├── RequestWorldSelectMenu.cpp │ └── EmoticonDataChanged.cpp ├── https │ ├── https.hpp │ ├── server_data.hpp │ ├── server_data.cpp │ └── https.cpp ├── database │ ├── shouhin.hpp │ ├── shouhin.cpp │ ├── world.hpp │ ├── peer.hpp │ ├── items.cpp │ ├── items.hpp │ └── peer.cpp ├── tools │ ├── ransuu.hpp │ ├── string.hpp │ ├── create_dialog.hpp │ ├── string.cpp │ └── create_dialog.cpp ├── packet │ ├── packet.hpp │ └── packet.cpp └── pch.hpp ├── Dockerfile ├── .gitignore ├── .github └── workflows │ ├── docker.yml │ └── make.yml ├── .vscode ├── c_cpp_properties.json ├── launch.json └── tasks.json ├── Makefile ├── windows-setup.bat ├── resources └── ctx │ ├── server.crt │ └── server.key ├── main.cpp ├── README.md ├── linux-setup.sh └── LICENSE /include/enet/lib/libenet.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gurotopia/Gurotopia/HEAD/include/enet/lib/libenet.a -------------------------------------------------------------------------------- /include/enet/lib/libenet_32.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gurotopia/Gurotopia/HEAD/include/enet/lib/libenet_32.a -------------------------------------------------------------------------------- /include/event_type/receive.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef RECEIVE_HPP 3 | #define RECEIVE_HPP 4 | 5 | extern void receive(ENetEvent& event); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/event_type/connect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef CONNECT_HPP 3 | #define CONNECT_HPP 4 | 5 | extern void _connect(ENetEvent& event); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/me.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ME_HPP 3 | #define ME_HPP 4 | 5 | extern void me(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/sb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SB_HPP 3 | #define SB_HPP 4 | 5 | extern void sb(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/edit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef EDIT_HPP 3 | #define EDIT_HPP 4 | 5 | extern void edit(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/find.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef FIND_HPP 3 | #define FIND_HPP 4 | 5 | extern void find(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/skin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SKIN_HPP 3 | #define SKIN_HPP 4 | 5 | extern void skin(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/warp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef WARP_HPP 3 | #define WARP_HPP 4 | 5 | extern void warp(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/who.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef WHO_HPP 3 | #define WHO_HPP 4 | 5 | extern void who(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/event_type/disconnect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef DISCONNECT_HPP 3 | #define DISCONNECT_HPP 4 | 5 | extern void disconnect(ENetEvent& event); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/state/movement.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MOVEMENT_HPP 3 | #define MOVEMENT_HPP 4 | 5 | extern void movement(ENetEvent& event, state state); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/commands/ghost.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef GHOST_HPP 3 | #define GHOST_HPP 4 | 5 | extern void ghost(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/state/ping_reply.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PING_REPLY_HPP 3 | #define PING_REPLY_HPP 4 | 5 | extern void ping_reply(ENetEvent& event, state state); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/state/tile_change.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TILE_CHANGE_HPP 3 | #define TILE_CHANGE_HPP 4 | 5 | extern void tile_change(ENetEvent& event, state state); 6 | 7 | #endif -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt update && apt install -y build-essential libssl-dev libsqlite3-dev 4 | 5 | COPY . . 6 | 7 | RUN make -j$(nproc) 8 | 9 | CMD ["/main.out"] -------------------------------------------------------------------------------- /include/commands/ageworld.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef AGEWORLD_HPP 3 | #define AGEWORLD_HPP 4 | 5 | extern void ageworld(ENetEvent& event, const std::string_view text); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/state/item_activate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ITEM_ACTIVATE_HPP 3 | #define ITEM_ACTIVATE_HPP 4 | 5 | extern void item_activate(ENetEvent& event, state state); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/state/tile_activate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TILE_ACTIVATE_HPP 3 | #define TILE_ACTIVATE_HPP 4 | 5 | extern void tile_activate(ENetEvent& event, state state); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/popup.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef POPUP_HPP 3 | #define POPUP_HPP 4 | 5 | extern void popup(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/on/SetBux.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SETBUX_HPP 3 | #define SETBUX_HPP 4 | 5 | namespace on 6 | { 7 | extern void SetBux(ENetEvent& event); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/state/__states.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __STATES_HPP 3 | #define __STATES_HPP 4 | 5 | extern std::unordered_map> state_pool; 6 | 7 | #endif -------------------------------------------------------------------------------- /include/event_type/disconnect.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "action/quit.hpp" 3 | #include "disconnect.hpp" 4 | 5 | void disconnect(ENetEvent& event) 6 | { 7 | action::quit(event, ""); 8 | } 9 | -------------------------------------------------------------------------------- /include/on/BillboardChange.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BILLBOARDCHANGE_HPP 2 | #define BILLBOARDCHANGE_HPP 3 | 4 | namespace on 5 | { 6 | extern void BillboardChange(ENetEvent& event); 7 | } 8 | 9 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/drop_item.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef DROP_ITEM_HPP 3 | #define DROP_ITEM_HPP 4 | 5 | extern void drop_item(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/find_item.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef FIND_ITEM_HPP 3 | #define FIND_ITEM_HPP 4 | 5 | extern void find_item(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/lock_edit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef LOCK_EDIT_HPP 3 | #define LOCK_EDIT_HPP 4 | 5 | extern void lock_edit(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/megaphone.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MEGAPHONE_HPP 3 | #define MEGAPHONE_HPP 4 | 5 | extern void megaphone(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/peer_edit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PEER_EDIT_HPP 3 | #define PEER_EDIT_HPP 4 | 5 | extern void peer_edit(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/event_type/__event_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef EVENT_TYPE_HPP 3 | #define EVENT_TYPE_HPP 4 | 5 | extern std::unordered_map> event_pool; 6 | 7 | #endif -------------------------------------------------------------------------------- /include/state/item_activate_object.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ITEM_ACTIVATE_OBJECT_HPP 3 | #define ITEM_ACTIVATE_OBJECT_HPP 4 | 5 | extern void item_activate_object(ENetEvent& event, state state); 6 | 7 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Makefile 2 | build/ 3 | 4 | # lingering files 5 | main.out 6 | main.exe 7 | items.dat 8 | server_data.php 9 | 10 | # VSC user settings 11 | .vscode/settings.json 12 | 13 | # SQL database 14 | db/ -------------------------------------------------------------------------------- /include/action/__action.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __ACTION_HPP 3 | #define __ACTION_HPP 4 | 5 | extern std::unordered_map> action_pool; 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/trash_item.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TRASH_ITEM_HPP 3 | #define TRASH_ITEM_HPP 4 | 5 | extern void trash_item(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/on/SetClothing.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SETCLOTHING_HPP 3 | #define SETCLOTHING_HPP 4 | 5 | namespace on 6 | { 7 | extern void SetClothing(ENetEvent& event); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/buy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef BUY_HPP 3 | #define BUY_HPP 4 | 5 | namespace action 6 | { 7 | extern void buy(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/create_blast.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef CREATE_BLAST_HPP 3 | #define CREATE_BLAST_HPP 4 | 5 | extern void create_blast(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/gateway_edit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef GATEWAY_EDIT_HPP 3 | #define GATEWAY_EDIT_HPP 4 | 5 | extern void gateway_edit(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/socialportal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SOCIALPORTAL_HPP 3 | #define SOCIALPORTAL_HPP 4 | 5 | extern void socialportal(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/on/NameChanged.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ONNAMECHANGED_HPP 3 | #define ONNAMECHANGED_HPP 4 | 5 | namespace on 6 | { 7 | extern void NameChanged(ENetEvent& event); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/state/ping_reply.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "ping_reply.hpp" 3 | 4 | void ping_reply(ENetEvent& event, state state) 5 | { 6 | printf("ping requested from %s\n", _peer[event.peer]->ltoken[0].c_str()); 7 | } -------------------------------------------------------------------------------- /include/action/drop.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef DROP_HPP 3 | #define DROP_HPP 4 | 5 | namespace action 6 | { 7 | extern void drop(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/info.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef INFO_HPP 3 | #define INFO_HPP 4 | 5 | namespace action 6 | { 7 | extern void info(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/input.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef INPUT_HPP 3 | #define INPUT_HPP 4 | 5 | namespace action 6 | { 7 | extern void input(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/quit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef QUIT_HPP 3 | #define QUIT_HPP 4 | 5 | namespace action 6 | { 7 | extern void quit(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/store.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef STORE_HPP 3 | #define STORE_HPP 4 | 5 | namespace action 6 | { 7 | extern void store(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/trash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TRASH_HPP 3 | #define TRASH_HPP 4 | 5 | namespace action 6 | { 7 | extern void trash(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/on/Action.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ACTION_HPP 3 | #define ACTION_HPP 4 | 5 | namespace on 6 | { 7 | extern void Action(ENetEvent& event, const std::string_view text); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/billboard_edit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef BILLBOARD_EDIT_HPP 3 | #define BILLBOARD_EDIT_HPP 4 | 5 | extern void billboard_edit(ENetEvent& event, const std::vector &&pipes); 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/wrench.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef WRENCH_HPP 3 | #define WRENCH_HPP 4 | 5 | namespace action 6 | { 7 | extern void wrench(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/commands/__command.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __COMMAND_HPP 3 | #define __COMMAND_HPP 4 | 5 | extern std::unordered_map> cmd_pool; 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/friends.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef FRIENDS_HPP 3 | #define FRIENDS_HPP 4 | 5 | namespace action 6 | { 7 | extern void friends(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/respawn.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef RESPAWN_HPP 3 | #define RESPAWN_HPP 4 | 5 | namespace action 6 | { 7 | extern void respawn(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/setSkin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SETSKIN_HPP 3 | #define SETSKIN_HPP 4 | 5 | namespace action 6 | { 7 | extern void setSkin(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/commands/punch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef CMD_PUNCH_HPP 3 | #define CMD_PUNCH_HPP 4 | 5 | extern u_char get_punch_id(u_int item_id); 6 | 7 | extern void punch(ENetEvent& event, const std::string_view text); 8 | 9 | #endif -------------------------------------------------------------------------------- /include/commands/weather.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef WEATHER_HPP 3 | #define WEATHER_HPP 4 | 5 | extern int get_weather_id(u_int item_id); 6 | 7 | extern void weather(ENetEvent& event, const std::string_view text); 8 | 9 | #endif -------------------------------------------------------------------------------- /include/action/enter_game.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ENTER_GAME_HPP 3 | #define ENTER_GAME_HPP 4 | 5 | namespace action 6 | { 7 | extern void enter_game(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/logging_in.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef LOGGING_IN_HPP 3 | #define LOGGING_IN_HPP 4 | 5 | namespace action 6 | { 7 | extern void logging_in(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/on/EmoticonDataChanged.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef EMOTICONDATACHANGED_HPP 3 | #define EMOTICONDATACHANGED_HPP 4 | 5 | namespace on 6 | { 7 | extern void EmoticonDataChanged(ENetEvent& event); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef DIALOG_RETURN_HPP 3 | #define DIALOG_RETURN_HPP 4 | 5 | namespace action 6 | { 7 | extern void dialog_return(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/itemfavourite.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ITEMFAVOURITE_HPP 3 | #define ITEMFAVOURITE_HPP 4 | 5 | namespace action 6 | { 7 | extern void itemfavourite(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/https/https.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef HTTPS_HPP 3 | #define HTTPS_HPP 4 | 5 | #include "server_data.hpp" // @todo make this independent 6 | 7 | namespace https 8 | { 9 | extern void listener(::server_data server_data); 10 | } 11 | 12 | #endif -------------------------------------------------------------------------------- /include/on/RequestWorldSelectMenu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ONREQUESTWORLDSELECTMENU_HPP 3 | #define ONREQUESTWORLDSELECTMENU_HPP 4 | 5 | namespace on 6 | { 7 | extern void RequestWorldSelectMenu(ENetEvent& event); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/__dialog_return.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __DIALOG_RETURN_HPP 3 | #define __DIALOG_RETURN_HPP 4 | 5 | extern std::unordered_map &&)>> dialog_return_pool; 6 | 7 | #endif -------------------------------------------------------------------------------- /include/action/quit_to_exit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef QUIT_TO_EXIT_HPP 3 | #define QUIT_TO_EXIT_HPP 4 | 5 | namespace action 6 | { 7 | extern void quit_to_exit(ENetEvent& event, const std::string& header, bool skip_selection); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/refresh_item_data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef REFRESH_ITEM_DATA_HPP 3 | #define REFRESH_ITEM_DATA_HPP 4 | 5 | namespace action 6 | { 7 | extern void refresh_item_data(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/inventoryfavuitrigger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef INVENTORYFAVUITRIGGER_HPP 3 | #define INVENTORYFAVUITRIGGER_HPP 4 | 5 | namespace action 6 | { 7 | extern void inventoryfavuitrigger(ENetEvent& event, const std::string& header); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/action/join_request.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef JOIN_REQUEST_HPP 3 | #define JOIN_REQUEST_HPP 4 | 5 | namespace action 6 | { 7 | extern void join_request(ENetEvent& event, const std::string& header, const std::string_view world_name); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/commands/ghost.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/SetClothing.hpp" 3 | #include "ghost.hpp" 4 | 5 | void ghost(ENetEvent& event, const std::string_view text) 6 | { 7 | auto &peer = _peer[event.peer]; 8 | 9 | peer->state ^= S_GHOST; 10 | 11 | on::SetClothing(event); 12 | } -------------------------------------------------------------------------------- /include/on/NameChanged.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "NameChanged.hpp" 3 | 4 | void on::NameChanged(ENetEvent& event) { 5 | auto &peer = _peer[event.peer]; 6 | 7 | packet::create(*event.peer, true, 0, { 8 | "OnNameChanged", 9 | std::format("`{}{}``", peer->prefix, peer->ltoken[0]).c_str() 10 | }); 11 | } -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Dockerfile 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | name: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 2025-12-16 12 | 13 | - run: docker build . --file Dockerfile 14 | -------------------------------------------------------------------------------- /include/action/dialog_return/megaphone.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "commands/sb.hpp" 4 | 5 | #include "megaphone.hpp" 6 | 7 | void megaphone(ENetEvent& event, const std::vector &&pipes) 8 | { 9 | if (pipes.size() < 7zu) return; 10 | 11 | sb(event, pipes[5zu]); // @todo handle this when /sb requires gems @todo handle trim 12 | } -------------------------------------------------------------------------------- /include/enet/utility.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file utility.h 3 | @brief ENet utility header 4 | */ 5 | #ifndef __ENET_UTILITY_H__ 6 | #define __ENET_UTILITY_H__ 7 | 8 | #define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) 9 | #define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) 10 | #define ENET_DIFFERENCE(x, y) ((x) < (y) ? (y) - (x) : (x) - (y)) 11 | 12 | #endif /* __ENET_UTILITY_H__ */ 13 | 14 | -------------------------------------------------------------------------------- /include/action/setSkin.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/SetClothing.hpp" 3 | #include "tools/string.hpp" 4 | #include "setSkin.hpp" 5 | 6 | void action::setSkin(ENetEvent& event, const std::string& header) 7 | { 8 | std::vector pipes = readch(header, '|'); 9 | 10 | _peer[event.peer]->skin_color = stoul(pipes[3zu]); // @todo handle non-numrials 11 | on::SetClothing(event); 12 | } -------------------------------------------------------------------------------- /include/enet/types.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file types.h 3 | @brief type definitions for ENet 4 | */ 5 | #ifndef __ENET_TYPES_H__ 6 | #define __ENET_TYPES_H__ 7 | 8 | typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ 9 | typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ 10 | typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ 11 | 12 | #endif /* __ENET_TYPES_H__ */ 13 | 14 | -------------------------------------------------------------------------------- /include/state/movement.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "movement.hpp" 3 | 4 | void movement(ENetEvent& event, state state) 5 | { 6 | auto &peer = _peer[event.peer]; 7 | 8 | peer->pos = { state.pos[0] / 32.0f, state.pos[1] / 32.0f }; 9 | peer->facing_left = state.peer_state & S_LEFT; 10 | state.netid = peer->netid; // @todo 11 | 12 | state_visuals(event, std::move(state)); // finished. 13 | } -------------------------------------------------------------------------------- /include/action/refresh_item_data.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "refresh_item_data.hpp" 3 | 4 | void action::refresh_item_data(ENetEvent& event, const std::string& header) 5 | { 6 | packet::create(*event.peer, false, 0, { 7 | "OnConsoleMessage", 8 | "One moment, updating item data..." 9 | }); 10 | enet_peer_send(event.peer, 0, enet_packet_create(im_data.data(), im_data.size(), ENET_PACKET_FLAG_RELIABLE)); 11 | } -------------------------------------------------------------------------------- /include/action/quit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "action/quit_to_exit.hpp" 3 | #include "quit.hpp" 4 | 5 | void action::quit(ENetEvent& event, const std::string& header) 6 | { 7 | action::quit_to_exit(event, "", true); 8 | 9 | if (event.peer == nullptr) return; 10 | if (event.peer->data != nullptr) 11 | { 12 | event.peer->data = nullptr; 13 | _peer.erase(event.peer); 14 | } 15 | enet_peer_reset(event.peer); 16 | } -------------------------------------------------------------------------------- /include/on/SetBux.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "SetBux.hpp" 3 | 4 | void on::SetBux(ENetEvent& event) 5 | { 6 | signed &gems = _peer[event.peer]->gems; 7 | static constexpr int signed_max = std::numeric_limits::max(); 8 | 9 | if (gems > signed_max) gems = signed_max; 10 | if (gems < 0) gems = 0; 11 | 12 | packet::create(*event.peer, false, 0, { 13 | "OnSetBux", 14 | gems, 15 | 1, 16 | 1 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /include/commands/find.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "find.hpp" 3 | 4 | void find(ENetEvent& event, const std::string_view text) 5 | { 6 | packet::create(*event.peer, false, 0, { 7 | "OnDialogRequest", 8 | "set_default_color|`o\n" 9 | "add_text_input|n|Search: ||26|\n" 10 | "add_searchable_item_list||sourceType:allItems;listType:iconWithCustomLabel;resultLimit:30|n|\n" 11 | "add_quick_exit|\n" 12 | "end_dialog|find_item|||" 13 | }); 14 | } -------------------------------------------------------------------------------- /include/event_type/__event_type.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "connect.hpp" 3 | #include "disconnect.hpp" 4 | #include "receive.hpp" 5 | #include "__event_type.hpp" 6 | 7 | std::unordered_map> event_pool 8 | { 9 | {::ENET_EVENT_TYPE_CONNECT, std::bind(&_connect, std::placeholders::_1)}, 10 | {::ENET_EVENT_TYPE_DISCONNECT, std::bind(&disconnect, std::placeholders::_1)}, 11 | {::ENET_EVENT_TYPE_RECEIVE, std::bind(&receive, std::placeholders::_1)}, 12 | }; 13 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${workspaceFolder}/include/**" 8 | ], 9 | "defines": [], 10 | "compilerPath": "c:/msys64/ucrt64/bin/g++.exe", 11 | "cStandard": "c23", 12 | "cppStandard": "c++23", 13 | "intelliSenseMode": "windows-gcc-x64" 14 | } 15 | ], 16 | "version": 4 17 | } -------------------------------------------------------------------------------- /include/on/Action.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "Action.hpp" 3 | 4 | void on::Action(ENetEvent& event, const std::string_view text) 5 | { 6 | std::string_view to_slang = 7 | (text == "facepalm") ? "fp" : 8 | (text == "shrug") ? "idk" : 9 | (text == "foldarms") ? "fold" : 10 | (text == "fa") ? "fold" : 11 | (text == "stubborn") ? "fold" : text; 12 | 13 | packet::create(*event.peer, true, 0, { 14 | "OnAction", 15 | ('/' + std::string(to_slang)).c_str() 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Run Gurotopia", 5 | "type": "cppvsdbg", 6 | "request": "launch", 7 | "program": "main.exe", 8 | "cwd": "${workspaceFolder}", 9 | "environment": [ 10 | { 11 | "name": "PATH", 12 | "value": "${env:PATH};C:/msys64/ucrt64/bin;C:/msys64/usr/bin" 13 | } 14 | ], 15 | "console": "integratedTerminal" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /include/action/dialog_return/find_item.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "tools/string.hpp" 4 | #include "on/SetClothing.hpp" 5 | 6 | #include "find_item.hpp" 7 | 8 | void find_item(ENetEvent& event, const std::vector &&pipes) 9 | { 10 | std::string id = readch(pipes[5zu], '_')[1]; // @note after searchableItemListButton 11 | 12 | _peer[event.peer]->emplace(slot(atoi(id.c_str()), 200)); 13 | inventory_visuals(event); 14 | on::SetClothing(event); // @note when a item gets added to inventory, clothing equiped resets.. 15 | } -------------------------------------------------------------------------------- /include/https/server_data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SERVER_DATA_HPP 3 | #define SERVER_DATA_HPP 4 | 5 | class server_data 6 | { 7 | public: 8 | std::string server{"127.0.0.1"}; 9 | u_short port{17091}; 10 | u_char type{1}; 11 | u_char type2{1}; 12 | std::string maint{"Server under maintenance. Please try again later."}; 13 | std::string loginurl{"login-gurotopia.vercel.app"}; 14 | std::string meta{"gurotopia"}; 15 | }; 16 | 17 | extern ::server_data init_server_data(); 18 | 19 | #endif -------------------------------------------------------------------------------- /include/on/BillboardChange.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "BillboardChange.hpp" 4 | 5 | void on::BillboardChange(ENetEvent& event) 6 | { 7 | auto &peer = _peer[event.peer]; 8 | packet::create(*event.peer, true, 0, { 9 | "OnBillboardChange", 10 | peer->netid, 11 | signed{peer->billboard.id}, 12 | std::format("{},{}", to_char(peer->billboard.show), to_char(peer->billboard.isBuying)).c_str(), 13 | peer->billboard.price, 14 | signed{peer->billboard.perItem} 15 | }); 16 | } -------------------------------------------------------------------------------- /include/action/dialog_return/lock_edit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "lock_edit.hpp" 4 | 5 | void lock_edit(ENetEvent& event, const std::vector &&pipes) 6 | { 7 | auto &peer = _peer[event.peer]; 8 | 9 | if (pipes[10] == "checkbox_public" && pipes[11] == "1"/*true*/ || pipes[11] == "0"/*false*/) 10 | { 11 | auto it = worlds.find(peer->recent_worlds.back()); 12 | if (it == worlds.end()) return; 13 | 14 | it->second._public = atoi(pipes[11].c_str()); 15 | 16 | // @todo add public lock visuals 17 | } 18 | } -------------------------------------------------------------------------------- /include/enet/time.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file time.h 3 | @brief ENet time constants and macros 4 | */ 5 | #ifndef __ENET_TIME_H__ 6 | #define __ENET_TIME_H__ 7 | 8 | #define ENET_TIME_OVERFLOW 86400000 9 | 10 | #define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) 11 | #define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) 12 | #define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) 13 | #define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) 14 | 15 | #define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) 16 | 17 | #endif /* __ENET_TIME_H__ */ 18 | 19 | -------------------------------------------------------------------------------- /include/action/respawn.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "respawn.hpp" 3 | 4 | void action::respawn(ENetEvent& event, const std::string& header) 5 | { 6 | packet::create(*event.peer, true, 0, { 7 | "OnSetFreezeState", 8 | 2 9 | }); 10 | packet::create(*event.peer, true, 0,{ "OnKilled" }); 11 | // @note wait 1900 milliseconds... 12 | auto &peer = _peer[event.peer]; 13 | packet::create(*event.peer, true, 1900, { 14 | "OnSetPos", 15 | std::vector{peer->rest_pos.front(), peer->rest_pos.back()} 16 | }); 17 | packet::create(*event.peer, true, 1900, { "OnSetFreezeState" }); 18 | } -------------------------------------------------------------------------------- /include/database/shouhin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SHOHIN_HPP 3 | #define SHOHIN_HPP 4 | 5 | class shouhin 6 | { 7 | public: 8 | std::string btn{}; 9 | std::string name{}; 10 | std::string rttx{}; 11 | std::string description{}; 12 | char tex1{}; 13 | char tex2{}; // @todo may have to change variable type... 14 | int cost{}; 15 | 16 | std::vector> im{}; // @note {id, amount} 17 | }; 18 | extern std::vector> shouhin_tachi; // @note {tab, shouhin} 19 | 20 | extern void init_shouhin_tachi(); 21 | 22 | #endif -------------------------------------------------------------------------------- /include/tools/ransuu.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct range 5 | { 6 | T front{}, back{}; 7 | }; 8 | 9 | class ransuu 10 | { 11 | std::mt19937 engine; // @todo change model(?) 12 | 13 | public: 14 | ransuu() : engine(std::random_device{}()) {} 15 | 16 | template 17 | T operator[](range _range) { 18 | std::uniform_int_distribution dist(_range.front, _range.back); 19 | return dist(engine); 20 | } 21 | 22 | template 23 | float shosu(range _range, float right = 0.1f) { 24 | return static_cast((*this)[_range]) * right; 25 | } 26 | }; -------------------------------------------------------------------------------- /include/action/dialog_return.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "tools/string.hpp" 4 | #include "dialog_return/__dialog_return.hpp" 5 | 6 | #include "action/dialog_return.hpp" 7 | 8 | void action::dialog_return(ENetEvent& event, const std::string& header) 9 | { 10 | auto &peer = _peer[event.peer]; 11 | std::vector pipes = readch(header, '|'); 12 | 13 | if (pipes.size() <= 3zu) return; // if button has no name or has no field. 14 | 15 | // @note found at ./action/dialog_return/ 16 | if (const auto it = dialog_return_pool.find(pipes[3zu]); it != dialog_return_pool.end()) 17 | it->second(std::ref(event), std::move(pipes)); 18 | } -------------------------------------------------------------------------------- /include/enet/callbacks.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file callbacks.h 3 | @brief ENet callbacks 4 | */ 5 | #ifndef __ENET_CALLBACKS_H__ 6 | #define __ENET_CALLBACKS_H__ 7 | 8 | #include 9 | 10 | typedef struct _ENetCallbacks 11 | { 12 | void * (ENET_CALLBACK * malloc) (size_t size); 13 | void (ENET_CALLBACK * free) (void * memory); 14 | void (ENET_CALLBACK * no_memory) (void); 15 | } ENetCallbacks; 16 | 17 | #ifdef __cplusplus 18 | extern "C" 19 | { 20 | #endif 21 | 22 | /** @defgroup callbacks ENet internal callbacks 23 | @{ 24 | @ingroup private 25 | */ 26 | 27 | extern void * enet_malloc (size_t); 28 | extern void enet_free (void *); 29 | 30 | /** @} */ 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif /* __ENET_CALLBACKS_H__ */ 37 | 38 | -------------------------------------------------------------------------------- /include/action/inventoryfavuitrigger.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/create_dialog.hpp" 3 | #include "inventoryfavuitrigger.hpp" 4 | 5 | void action::inventoryfavuitrigger(ENetEvent& event, const std::string& header) 6 | { 7 | packet::create(*event.peer, false, 0, { 8 | "OnDialogRequest", 9 | create_dialog() 10 | .set_default_color("`o") 11 | .add_label_with_icon("big", "`wFavorited Items``", 13814) 12 | .add_spacer("small") 13 | .add_textbox("All favorited items are currently in your inventory. They can be unfavorited by tapping on the UNFAV button while having the item selected in your inventory.") 14 | .add_spacer("small") 15 | .end_dialog("unfavorite_items_dialog", "Close", "").c_str() 16 | }); 17 | } -------------------------------------------------------------------------------- /include/action/dialog_return/trash_item.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "trash_item.hpp" 4 | 5 | void trash_item(ENetEvent& event, const std::vector &&pipes) 6 | { 7 | const short id = atoi(pipes[5zu].c_str()); 8 | short count = atoi(pipes[8zu].c_str()); 9 | 10 | for (const ::slot &slot : _peer[event.peer]->slots) 11 | if (slot.id == id) 12 | if (count > slot.count) count = slot.count; 13 | else if (count < 0) count = 0; 14 | 15 | _peer[event.peer]->emplace(slot(id, -count)); // @note take away 16 | modify_item_inventory(event, {id, count}); 17 | 18 | packet::create(*event.peer, false, 0, { 19 | "OnConsoleMessage", 20 | std::format("{} `w{}`` recycled, `w0`` gems earned.", count, items[id].raw_name).c_str() 21 | }); 22 | } -------------------------------------------------------------------------------- /include/commands/skin.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/SetClothing.hpp" 3 | #include "tools/string.hpp" 4 | #include "skin.hpp" 5 | 6 | void skin(ENetEvent& event, const std::string_view text) 7 | { 8 | if (text.length() <= sizeof("skin ") - 1) 9 | { 10 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "Usage: /skin `w{id}``" }); 11 | return; 12 | } 13 | std::string id{ text.substr(sizeof("skin ")-1) }; 14 | 15 | try 16 | { 17 | _peer[event.peer]->skin_color = stol(id); 18 | on::SetClothing(event); 19 | } 20 | catch (const std::invalid_argument &ex) 21 | { 22 | packet::create(*event.peer, false, 0, { 23 | "OnConsoleMessage", 24 | "`4Invalid input. ``id must be a `wnumber``." 25 | }); 26 | } 27 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "label": "Build Gurotopia", 5 | "type": "cppbuild", 6 | "command": "c:/msys64/usr/bin/bash.exe", 7 | "args": [ 8 | "-c", 9 | "export PATH=\"$PATH:/c/msys64/ucrt64/bin:/c/msys64/usr/bin\" && make -j$(nproc)" 10 | ], 11 | "group": { 12 | "kind": "build", 13 | "isDefault": true 14 | } 15 | }, 16 | { 17 | "label": "Clean Gurotopia", 18 | "type": "cppbuild", 19 | "command": "c:/msys64/usr/bin/bash.exe", 20 | "args": [ 21 | "-c", 22 | "export PATH=\"$PATH:/c/msys64/usr/bin\" && make clean" 23 | ] 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /include/action/dialog_return/drop_item.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "drop_item.hpp" 4 | 5 | void drop_item(ENetEvent& event, const std::vector &&pipes) 6 | { 7 | auto &peer = _peer[event.peer]; 8 | 9 | const short id = atoi(pipes[5zu].c_str()); 10 | short count = atoi(pipes[8zu].c_str()); 11 | 12 | for (const ::slot &slot : _peer[event.peer]->slots) 13 | if (slot.id == id) 14 | if (count > slot.count) count = slot.count; 15 | else if (count < 0) count = 0; 16 | 17 | peer->emplace(slot(id, -count)); // @note take away 18 | modify_item_inventory(event, {id, count}); 19 | 20 | float x_nabor = (peer->facing_left ? peer->pos[0] - 1 : peer->pos[0] + 1); // @note peer's naboring tile (drop position) 21 | item_change_object(event, {id, count}, {x_nabor, peer->pos[1]}); 22 | } -------------------------------------------------------------------------------- /include/action/friends.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/create_dialog.hpp" 3 | #include "friends.hpp" 4 | 5 | void action::friends(ENetEvent& event, const std::string& header) 6 | { 7 | packet::create(*event.peer, false, 0, { 8 | "OnDialogRequest", 9 | create_dialog() 10 | .set_default_color("`o") 11 | .add_label_with_icon("big", " `wSocial Portal`` ", 1366) 12 | .add_spacer("small") 13 | .add_button("showfriend", "`wShow Friends``") 14 | .add_button("communityhub", "`wCommunity Hub``") 15 | .add_button("show_apprentices", "`wShow Apprentices``") 16 | .add_button("showguild", "`wCreate Guild``") 17 | .add_button("trade_history", "`wTrade History``") 18 | .add_quick_exit() 19 | .end_dialog("socialportal", "").c_str() 20 | }); 21 | } -------------------------------------------------------------------------------- /include/state/__states.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "movement.hpp" 3 | #include "tile_change.hpp" 4 | #include "tile_activate.hpp" 5 | #include "item_activate.hpp" 6 | #include "item_activate_object.hpp" 7 | #include "ping_reply.hpp" 8 | #include "__states.hpp" 9 | 10 | std::unordered_map> state_pool 11 | { 12 | {0x00, std::bind(&movement, std::placeholders::_1, std::placeholders::_2)}, 13 | {0x03, std::bind(&tile_change, std::placeholders::_1, std::placeholders::_2)}, 14 | {0x07, std::bind(&tile_activate, std::placeholders::_1, std::placeholders::_2)}, 15 | {0x0a, std::bind(&item_activate, std::placeholders::_1, std::placeholders::_2)}, 16 | {0x0b, std::bind(&item_activate_object, std::placeholders::_1, std::placeholders::_2)}, 17 | {0x15, std::bind(&ping_reply, std::placeholders::_1, std::placeholders::_2)} 18 | }; -------------------------------------------------------------------------------- /include/commands/punch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/SetClothing.hpp" 3 | #include "punch.hpp" 4 | 5 | u_char get_punch_id(u_int item_id) 6 | { 7 | switch (item_id) 8 | { 9 | // @todo 10 | default: return 0; 11 | } 12 | } 13 | 14 | void punch(ENetEvent& event, const std::string_view text) 15 | { 16 | if (text.length() <= sizeof("punch ") - 1) 17 | { 18 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "Usage: /punch `w{id}``" }); 19 | return; 20 | } 21 | std::string id{ text.substr(sizeof("punch ")-1) }; 22 | try 23 | { 24 | _peer[event.peer]->punch_effect = stoi(id); 25 | on::SetClothing(event); 26 | } 27 | catch (const std::invalid_argument &ex) 28 | { 29 | packet::create(*event.peer, false, 0, { 30 | "OnConsoleMessage", 31 | "`4Invalid input. ``id must be a `wnumber``." 32 | }); 33 | } 34 | } -------------------------------------------------------------------------------- /include/commands/warp.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "action/join_request.hpp" 3 | #include "action/quit_to_exit.hpp" 4 | #include "warp.hpp" 5 | 6 | void warp(ENetEvent& event, const std::string_view text) 7 | { 8 | if (text.length() <= sizeof("warp ") - 1) 9 | { 10 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "Usage: /warp `w{world name}``" }); 11 | return; 12 | } 13 | std::string world_name{ text.substr(sizeof("warp ") - 1) }; 14 | std::for_each(world_name.begin(), world_name.end(), [](char& c) { c = std::toupper(c); }); 15 | 16 | packet::action(*event.peer, "log", std::format("msg| `6/warp {}``", world_name)); 17 | packet::create(*event.peer, false, 0, { "OnSetFreezeState", 1 }); 18 | packet::action(*event.peer, "log", std::format("msg|Magically warping to world `5{}``...", world_name)); 19 | 20 | action::quit_to_exit(event, "", true); 21 | action::join_request(event, "", world_name); 22 | } 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX := g++ 2 | CXXFLAGS := -std=c++2b -g -Iinclude -MMD -MP 3 | LIBS := -L./include/enet/lib -lssl -lcrypto -lsqlite3 4 | 5 | BUILD_DIR := build 6 | 7 | ifeq ($(OS),Windows_NT) 8 | LIBS += -lenet_32 -lws2_32 -lwinmm 9 | OUTPUT := main.exe 10 | else 11 | LIBS += -lenet 12 | OUTPUT := main.out 13 | endif 14 | 15 | all: $(OUTPUT) 16 | 17 | SOURCES := main.cpp \ 18 | $(wildcard include/*.cpp) \ 19 | $(wildcard include/**/*.cpp) \ 20 | $(wildcard include/**/**/*.cpp) 21 | 22 | OBJECTS := $(SOURCES:%.cpp=$(BUILD_DIR)/%.o) 23 | DEPS := $(OBJECTS:.o=.d) 24 | 25 | $(OUTPUT): $(OBJECTS) 26 | $(CXX) $(OBJECTS) -o $@ $(LIBS) 27 | 28 | $(BUILD_DIR)/pch.gch: include/pch.hpp | $(BUILD_DIR) 29 | $(CXX) $(CXXFLAGS) -Iinclude -x c++-header $< -o $@ 30 | 31 | $(BUILD_DIR)/%.o: %.cpp $(BUILD_DIR)/pch.gch | $(BUILD_DIR) 32 | @mkdir -p $(dir $@) 33 | $(CXX) $(CXXFLAGS) -c $< -o $@ 34 | 35 | $(BUILD_DIR): 36 | @mkdir -p $@ 37 | 38 | -include $(DEPS) 39 | 40 | clean: 41 | rm -rf $(BUILD_DIR) 42 | -------------------------------------------------------------------------------- /include/event_type/connect.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "action/quit.hpp" 3 | #include "connect.hpp" 4 | 5 | void _connect(ENetEvent& event) 6 | { 7 | if (peers(event, PEER_ALL).size() > server->peerCount) 8 | { 9 | packet::action(*event.peer, "log", 10 | std::format( 11 | "msg|`4SERVER OVERLOADED`` : Sorry, our servers are currently at max capacity with {} online, please try later. We are working to improve this!", 12 | server->peerCount 13 | )); 14 | packet::action(*event.peer, "logon_fail", ""); // @note triggers action|quit on client. 15 | } 16 | else 17 | { 18 | enet_peer_send(event.peer, 0, enet_packet_create("\x01\x00\x00\x00", 4zu, ENET_PACKET_FLAG_RELIABLE)); // @note 01 00 00 00 19 | 20 | std::shared_ptr peer_data = std::make_shared(); 21 | event.peer->data = peer_data.get(); 22 | _peer.emplace(event.peer, std::move(peer_data)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /include/packet/packet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PACKET_HPP 3 | #define PACKET_HPP 4 | 5 | #include 6 | 7 | namespace packet 8 | { 9 | /* 10 | @param p short for peer, the peer who will receive this packet, this can also be used with peers() to send to multiple peers. 11 | @param netid to my knowledge this value should be true if it relates to a peer's state in a world (OnRemove, OnSpawn OnChangeSkin, ect), else false (OnConsoleMessage, OnTalkBubble, ect.). 12 | @param params list of param that structures your packet. each entry will be than identified as a const char* or signed/unsigned or float/double, 13 | respectfully void* entires will not be accepted. e.g. classes, ptr, void 14 | */ 15 | extern void create(ENetPeer& p, bool netid, signed delay, const std::vector& params); 16 | 17 | extern void action(ENetPeer& p, const std::string& action, const std::string& str); 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /include/commands/who.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "who.hpp" 3 | 4 | void who(ENetEvent& event, const std::string_view text) 5 | { 6 | auto &peer = _peer[event.peer]; 7 | std::string list; 8 | 9 | peers(event, PEER_SAME_WORLD, [&peer, event, &list](ENetPeer& p) 10 | { 11 | auto &w_peer = _peer[&p]; // @note 'w' is just short for world. so world_peer 12 | std::string full_name = std::format("`{}{}", w_peer->prefix, w_peer->ltoken[0]); 13 | if (w_peer->user_id != peer->user_id) 14 | { 15 | packet::create(*event.peer, false, 0, { 16 | "OnTalkBubble", 17 | w_peer->netid, 18 | full_name.c_str(), 19 | 1u 20 | }); 21 | } 22 | if (!list.empty()) list += ", "; 23 | list.append(std::move(full_name)); 24 | }); 25 | packet::action(*event.peer, "log", std::format( 26 | "msg|`wWho's in `${}``:`` {}``", 27 | peer->recent_worlds.back(), list 28 | )); 29 | } 30 | -------------------------------------------------------------------------------- /include/commands/me.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "me.hpp" 3 | 4 | void me(ENetEvent& event, const std::string_view text) 5 | { 6 | if (text.length() <= sizeof("me ") - 1) 7 | { 8 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "Usage: /me `w{message}``" }); 9 | return; 10 | } 11 | std::string message{ text.substr(sizeof("me ")-1) }; 12 | auto &peer = _peer[event.peer]; 13 | 14 | // @todo 15 | peers(event, PEER_SAME_WORLD, [&peer, message](ENetPeer& p) 16 | { 17 | packet::create(p, false, 0, { 18 | "OnTalkBubble", 19 | peer->netid, 20 | std::format("player_chat= `6<```{}{}`` `#{}```6>``", 21 | peer->prefix, peer->ltoken[0], message).c_str(), 22 | 0u 23 | }); 24 | packet::create(p, false, 0, { 25 | "OnConsoleMessage", 26 | std::format("CP:0_PL:0_OID:__CT:[W]_ `6<```{}{}`` `#{}```6>``", 27 | peer->prefix, peer->ltoken[0], message).c_str() 28 | }); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /include/action/dialog_return/create_blast.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "action/quit_to_exit.hpp" // @note peer leave world 4 | #include "action/join_request.hpp" // @note peer enter (blast) world 5 | 6 | #include "create_blast.hpp" 7 | 8 | void create_blast(ENetEvent& event, const std::vector &&pipes) 9 | { 10 | const u_short id = atoi(pipes[5zu].c_str()); 11 | std::string world_name = pipes[8zu]; 12 | 13 | std::for_each(world_name.begin(), world_name.end(), [](char& c) { c = std::toupper(c); }); 14 | 15 | switch (id) 16 | { 17 | case 1402: // @note Thermonuclear Blast 18 | { 19 | auto [it, inserted] = worlds.try_emplace(world_name, world_name); 20 | world &world = it->second; 21 | if (world.name.empty()) 22 | { 23 | action::quit_to_exit(event, "", true); 24 | blast::thermonuclear(world, world_name); 25 | action::join_request(event, "", world_name); 26 | } 27 | break; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /include/action/itemfavourite.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "itemfavourite.hpp" 4 | 5 | void action::itemfavourite(ENetEvent& event, const std::string& header) 6 | { 7 | std::string id{readch(header, '|')[4]}; 8 | if (id.empty()) return; 9 | 10 | auto &peer = _peer[event.peer]; 11 | auto it = std::ranges::find(peer->fav, stoi(id)); 12 | bool fav = it != peer->fav.end(); 13 | if (peer->fav.size() >= 20 && !fav) 14 | { 15 | constexpr std::string_view message = "You cannot favorite any more items. Remove some from your list and try again."; 16 | packet::create(*event.peer, false, 0, { "OnTalkBubble", peer->netid, message.data(), 0u, 1u }); 17 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", message.data() }); 18 | return; 19 | } 20 | 21 | packet::create(*event.peer, false, 0, { 22 | "OnFavItemUpdated", 23 | stoi(id), 24 | (fav) ? 0 : 1 25 | }); 26 | if (fav) peer->fav.erase(it); 27 | else peer->fav.emplace_back(stoi(id)); 28 | } 29 | -------------------------------------------------------------------------------- /include/pch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PCH_HPP 3 | #define PCH_HPP 4 | 5 | #include "enet/enet.h" // @version SHA: 2b22def89210ca86b729a22a94a60bbacc9667f2 25-03-22 | https://github.com/ZTzTopia/enet 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "database/items.hpp" 20 | #include "database/peer.hpp" 21 | #include "database/world.hpp" 22 | #include "packet/packet.hpp" 23 | 24 | #if defined(_MSC_VER) 25 | /* cause MSVC does not know 'zu' when the compiler(MSBuild) does... */ 26 | #pragma warning(disable: 4455) 27 | constexpr std::size_t operator"" zu(std::size_t size) { 28 | return size; 29 | } 30 | 31 | #endif 32 | 33 | /* @todo have this compile in files of use */ 34 | constexpr std::byte PACKET_CREATE{ 04 }; 35 | constexpr std::byte PACKET_STATE{ 0x08 }; 36 | 37 | #endif -------------------------------------------------------------------------------- /windows-setup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Gurotopia installer 2025-11-14 sha-46f252d2c3dcadb7755e8d6bf3a87e7cf87fe128 3 | 4 | if not exist "%USERPROFILE%\AppData\Local\Programs\Microsoft VS Code\Code.exe" ( 5 | powershell -Command "Start-BitsTransfer -Source 'https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user' -Destination 'installer.exe'" 6 | installer.exe /silent /mergetasks=!runcode 7 | del installer.exe 8 | ) 9 | 10 | where code >nul 2>nul && ( 11 | code --list-extensions | findstr /I "ms-vscode.cpptools" >nul || ( 12 | code --install-extension ms-vscode.cpptools 13 | ) 14 | ) 15 | 16 | if not exist "C:\msys64\usr\bin\bash.exe" ( 17 | powershell -Command "Start-BitsTransfer -Source 'https://github.com/msys2/msys2-installer/releases/latest/download/msys2-x86_64-latest.exe' -Destination installer.exe" 18 | installer.exe --confirm-command --accept-messages --no-start 19 | del installer.exe 20 | ) 21 | 22 | C:\msys64\usr\bin\bash.exe -lc "pacman -S --needed --noconfirm mingw-w64-ucrt-x86_64-{gcc,openssl,sqlite} make" 23 | 24 | :: open Gurotopia in vscode @todo automatically build Gurotopia. 25 | code . main.cpp 26 | -------------------------------------------------------------------------------- /include/action/dialog_return/billboard_edit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "on/BillboardChange.hpp" 4 | 5 | #include "billboard_edit.hpp" 6 | 7 | void billboard_edit(ENetEvent& event, const std::vector &&pipes) 8 | { 9 | auto &peer = _peer[event.peer]; 10 | 11 | if (pipes[4zu] == "billboard_item") 12 | { 13 | const short billboard_item = atoi(pipes[5zu].c_str()); 14 | 15 | if (billboard_item == 18 || billboard_item == 32) return; 16 | 17 | peer->billboard = { 18 | .id = billboard_item, 19 | .show = stoi(pipes[7zu]) != 0, 20 | .isBuying = stoi(pipes[9zu]) != 0, 21 | .price = stoi(pipes[11zu]), 22 | .perItem = stoi(pipes[13zu]) != 0, 23 | }; 24 | } 25 | else // @note billboard_toggle 26 | { 27 | peer->billboard = { 28 | .id = peer->billboard.id, 29 | .show = stoi(pipes[5zu]) != 0, 30 | .isBuying = stoi(pipes[7zu]) != 0, 31 | .price = stoi(pipes[9zu]), 32 | .perItem = stoi(pipes[11zu]) != 0, 33 | }; 34 | } 35 | on::BillboardChange(event); 36 | } -------------------------------------------------------------------------------- /include/commands/ageworld.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "ageworld.hpp" 3 | 4 | #if defined(_MSC_VER) 5 | using namespace std::chrono; 6 | #else 7 | using namespace std::chrono::_V2; 8 | #endif 9 | using namespace std::literals::chrono_literals; 10 | 11 | void ageworld(ENetEvent& event, const std::string_view text) 12 | { 13 | auto &peer = _peer[event.peer]; 14 | 15 | if (!worlds.contains(peer->recent_worlds.back())) return; 16 | ::world &world = worlds.at(peer->recent_worlds.back()); 17 | 18 | std::vector &blocks = world.blocks; 19 | for (std::size_t i = 0zu; i < blocks.size(); ++i) 20 | { 21 | block &block = blocks[i]; 22 | ::item &item = items[block.fg]; 23 | if (item.type == type::PROVIDER || item.type == type::SEED) // @todo 24 | { 25 | block.tick -= 86400s; 26 | tile_update(event, 27 | { 28 | .id = block.fg, 29 | .punch = ::pos{ (short)i % 100, (short)i / 100 } 30 | }, block, world); 31 | } 32 | } 33 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "aged world by `w1 day``." }); 34 | } -------------------------------------------------------------------------------- /include/database/shouhin.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "shouhin.hpp" 4 | 5 | std::vector> shouhin_tachi{}; 6 | 7 | void init_shouhin_tachi() 8 | { 9 | std::ifstream file("resources/store.txt"); 10 | for (std::string line; std::getline(file, line); ) 11 | { 12 | if (line.empty() || line.starts_with("#")) continue; // @note '#' initiates a comment 13 | std::vector pipes = readch(line, '|'); 14 | ::shouhin shouhin{ 15 | .btn = pipes[1], 16 | .name = pipes[2], 17 | .rttx = pipes[3], 18 | .description = pipes[4], 19 | .tex1 = pipes[5].front(), 20 | .tex2 = pipes[6].front(), // @todo 21 | .cost = stoi(pipes[7]) 22 | }; 23 | std::vector tachi = readch(pipes[8], ','); 24 | for (std::string &im : tachi) 25 | { 26 | std::vector co = readch(im, ':'); // @note 'co' short for colon 27 | shouhin.im.emplace_back(stoi(co[0]), stoi(co[1])); 28 | } 29 | shouhin_tachi.emplace_back(stoi(pipes[0]), shouhin); 30 | } 31 | } -------------------------------------------------------------------------------- /.github/workflows/make.yml: -------------------------------------------------------------------------------- 1 | name: Makefile 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | jobs: 7 | build: 8 | runs-on: ${{ matrix.os }} 9 | name: "${{ matrix.os }}" 10 | strategy: 11 | matrix: 12 | os: [windows-latest, ubuntu-latest] 13 | steps: 14 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 2025-12-16 15 | 16 | 17 | - if: matrix.os == 'windows-latest' 18 | uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0 19 | with: 20 | msystem: UCRT64 21 | update: true 22 | install: >- 23 | mingw-w64-ucrt-x86_64-gcc 24 | mingw-w64-ucrt-x86_64-openssl 25 | mingw-w64-ucrt-x86_64-sqlite 26 | make 27 | 28 | - if: matrix.os == 'ubuntu-latest' 29 | run: sudo apt-get update && sudo apt-get install build-essential libssl-dev openssl sqlite3 30 | 31 | 32 | - if: matrix.os == 'windows-latest' 33 | run: make -j$(nproc) 34 | shell: msys2 {0} 35 | 36 | - if: matrix.os == 'ubuntu-latest' 37 | run: make -j$(nproc) 38 | # assume bash 39 | -------------------------------------------------------------------------------- /include/tools/string.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TOOLS_STRING_HPP 3 | #define TOOLS_STRING_HPP 4 | 5 | /* 6 | @param str the whole string 7 | @param c the char to search for and split 8 | @return std::vector storing each split off from c found in the str. 9 | */ 10 | extern std::vector readch(const std::string &str, char c); 11 | 12 | /* 13 | @return true if string contains ONLY alphabet [a, b, c] or number [1, 2, 3] 14 | */ 15 | extern bool alpha(const std::string& str); 16 | 17 | /* 18 | @return true if string contains ONLY number [1, 2, 3] 19 | */ 20 | extern bool number(const std::string& str); 21 | 22 | /* 23 | @return true if string contains ONLY numbers or alphabet [1, 2, 3, a, b, c] 24 | */ 25 | extern bool alnum(const std::string& str); 26 | 27 | extern std::string base64_decode(const std::string& encoded); 28 | 29 | // @todo downgrade to a int (4 bit) 30 | extern std::size_t fnv1a(const std::string& value) noexcept; 31 | 32 | /* 33 | @return '1' (true) || '0' (false) 34 | */ 35 | inline constexpr auto to_char = [](bool b) { return b ? '1' : '0'; }; 36 | 37 | 38 | #endif -------------------------------------------------------------------------------- /include/action/trash.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "tools/create_dialog.hpp" 4 | #include "trash.hpp" 5 | 6 | void action::trash(ENetEvent& event, const std::string& header) 7 | { 8 | std::string itemID = readch(header, '|')[4]; 9 | 10 | item &item = items[atoi(itemID.c_str())]; 11 | 12 | if (item.cat == CAT_CANNOT_DROP) 13 | { 14 | packet::create(*event.peer, false, 0, { "OnTextOverlay", "You'd be sorry if you lost that!" }); 15 | return; 16 | } 17 | 18 | for (const ::slot &slot : _peer[event.peer]->slots) 19 | if (slot.id == item.id) 20 | { 21 | packet::create(*event.peer, false, 0, { 22 | "OnDialogRequest", 23 | create_dialog() 24 | .set_default_color("`o") 25 | .add_label_with_icon("big", std::format("`4Recycle`` `w{}``", item.raw_name), slot.id) 26 | .add_textbox(std::format("How many to `4destroy``? (you have {})", slot.count)) 27 | .add_text_input("count", "", 0, 5) 28 | .embed_data("itemID", slot.id) 29 | .end_dialog("trash_item").c_str() 30 | }); 31 | return; 32 | } 33 | } -------------------------------------------------------------------------------- /include/action/drop.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "tools/create_dialog.hpp" 4 | #include "drop.hpp" 5 | 6 | void action::drop(ENetEvent& event, const std::string& header) 7 | { 8 | std::string itemID = readch(header, '|')[4]; 9 | 10 | item &item = items[atoi(itemID.c_str())]; 11 | 12 | if (item.cat == CAT_CANNOT_DROP) 13 | { 14 | packet::create(*event.peer, false, 0, { "OnTextOverlay", "You can't drop that." }); 15 | return; 16 | } 17 | 18 | for (const ::slot &slot : _peer[event.peer]->slots) 19 | if (slot.id == item.id) 20 | { 21 | packet::create(*event.peer, false, 0, { 22 | "OnDialogRequest", 23 | create_dialog() 24 | .set_default_color("`o") 25 | .add_label_with_icon("big", std::format("`wDrop {}``", item.raw_name), item.id) 26 | .add_textbox("How many to drop?") 27 | .add_text_input("count", "", slot.count, 5) 28 | .embed_data("itemID", item.id) 29 | .end_dialog("drop_item").c_str() // @todo handle c_str(); make packet accept std::string. 30 | }); 31 | return; 32 | } 33 | } -------------------------------------------------------------------------------- /include/commands/sb.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "sb.hpp" 3 | 4 | void sb(ENetEvent& event, const std::string_view text) 5 | { 6 | if (text.length() <= sizeof("sb ") - 1) 7 | { 8 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "Usage: /sb `w{message}``" }); 9 | return; 10 | } 11 | std::string message{ text.substr(sizeof("sb ")-1) }; 12 | auto &peer = _peer[event.peer]; 13 | 14 | auto it = worlds.find(peer->recent_worlds.back()); 15 | if (it == worlds.end()) return; 16 | 17 | std::string display = peer->recent_worlds.back(); 18 | for (::block &block : it->second.blocks) 19 | if (block.fg == 226 && block.state3 & S_TOGGLE) 20 | { 21 | display = "`4JAMMED``"; 22 | break; // @note we don't care if other signals are toggled. 23 | } 24 | 25 | peers(event, PEER_ALL, [&peer, message, display](ENetPeer& p) 26 | { 27 | packet::create(p, false, 0, { 28 | "OnConsoleMessage", 29 | std::format( 30 | "CP:0_PL:0_OID:_CT:[SB]_ `5** from (`{}{}`````5) in [```${}```5] ** : ```${}``", 31 | peer->prefix, peer->ltoken[0], display, message 32 | ).c_str() 33 | }); 34 | }); 35 | } -------------------------------------------------------------------------------- /include/state/item_activate_object.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/SetBux.hpp" 3 | #include "item_activate_object.hpp" 4 | 5 | #include 6 | 7 | void item_activate_object(ENetEvent& event, state state) 8 | { 9 | auto &peer = _peer[event.peer]; 10 | 11 | if (!worlds.contains(peer->recent_worlds.back())) return; 12 | ::world &world = worlds.at(peer->recent_worlds.back()); 13 | 14 | auto f = world.ifloats.find(state.id); 15 | if (f == world.ifloats.end()) return; 16 | ::ifloat &ifloat = f->second; 17 | 18 | ::item &item = items[ifloat.id]; 19 | if (item.type != type::GEM) 20 | { 21 | packet::create(*event.peer, false, 0, { 22 | "OnConsoleMessage", 23 | (item.rarity >= 999) ? 24 | std::format("Collected `w{} {}``.", ifloat.count, item.raw_name).c_str() : 25 | std::format("Collected `w{} {}``. Rarity: `w{}``", ifloat.count, item.raw_name, item.rarity).c_str() 26 | }); 27 | ifloat.count = peer->emplace(slot{ifloat.id, ifloat.count}); 28 | } 29 | else 30 | { 31 | peer->gems += ifloat.count; 32 | ifloat.count = 0; 33 | on::SetBux(event); 34 | } 35 | item_change_object(event, {ifloat.id, ifloat.count}, ifloat.pos, state.id/*@todo*/); 36 | if (ifloat.count == 0) world.ifloats.erase(f); 37 | } -------------------------------------------------------------------------------- /include/action/dialog_return/peer_edit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "on/NameChanged.hpp" // @note peer name changes when role updates 4 | #include "on/SetBux.hpp" // @note update gem count @todo if changed. (currently it updates everytime peer is edited) 5 | 6 | #include "peer_edit.hpp" 7 | 8 | void peer_edit(ENetEvent& event, const std::vector &&pipes) 9 | { 10 | const std::string name = pipes[5zu]; 11 | const bool status = atoi(pipes[8zu].c_str()); 12 | 13 | const u_char role = atoi(pipes[11zu].c_str()); 14 | const short level = atoi(pipes[13zu].c_str()); 15 | const signed gems = atoi(pipes[15zu].c_str()); 16 | 17 | if (status) // @note online 18 | { 19 | peers(event, PEER_ALL, [&event, name, role, level, gems](ENetPeer& p) 20 | { 21 | if (_peer[&p]->ltoken[0] == name) 22 | { 23 | auto &_p = _peer[&p]; 24 | _p->role = role; 25 | _p->level[0] = level; 26 | _p->gems = gems; 27 | 28 | on::NameChanged(event); 29 | on::SetBux(event); 30 | return; 31 | } 32 | }); 33 | } 34 | else // @note offline 35 | { 36 | ::peer &offline = ::peer().read(name); 37 | offline.role = role; 38 | offline.level[0] = level; 39 | offline.gems = gems; 40 | } 41 | } -------------------------------------------------------------------------------- /include/enet/list.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file list.h 3 | @brief ENet list management 4 | */ 5 | #ifndef __ENET_LIST_H__ 6 | #define __ENET_LIST_H__ 7 | 8 | #include 9 | 10 | typedef struct _ENetListNode 11 | { 12 | struct _ENetListNode * next; 13 | struct _ENetListNode * previous; 14 | } ENetListNode; 15 | 16 | typedef ENetListNode * ENetListIterator; 17 | 18 | typedef struct _ENetList 19 | { 20 | ENetListNode sentinel; 21 | } ENetList; 22 | 23 | #ifdef __cplusplus 24 | extern "C" 25 | { 26 | #endif 27 | 28 | extern void enet_list_clear (ENetList *); 29 | 30 | extern ENetListIterator enet_list_insert (ENetListIterator, void *); 31 | extern void * enet_list_remove (ENetListIterator); 32 | extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); 33 | 34 | extern size_t enet_list_size (ENetList *); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #define enet_list_begin(list) ((list) -> sentinel.next) 41 | #define enet_list_end(list) (& (list) -> sentinel) 42 | 43 | #define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) 44 | 45 | #define enet_list_next(iterator) ((iterator) -> next) 46 | #define enet_list_previous(iterator) ((iterator) -> previous) 47 | 48 | #define enet_list_front(list) ((void *) (list) -> sentinel.next) 49 | #define enet_list_back(list) ((void *) (list) -> sentinel.previous) 50 | 51 | #endif /* __ENET_LIST_H__ */ 52 | 53 | -------------------------------------------------------------------------------- /include/on/SetClothing.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "SetClothing.hpp" 3 | 4 | void on::SetClothing(ENetEvent& event) 5 | { 6 | auto &peer = _peer[event.peer]; 7 | 8 | packet::create(*event.peer, true, 0, { 9 | "OnSetClothing", 10 | std::vector{peer->clothing[hair], peer->clothing[shirt], peer->clothing[legs]}, 11 | std::vector{peer->clothing[feet], peer->clothing[face], peer->clothing[hand]}, 12 | std::vector{peer->clothing[back], peer->clothing[head], peer->clothing[charm]}, 13 | (peer->state & S_GHOST) ? -140 : peer->skin_color, 14 | std::vector{peer->clothing[ances], 0.0f, 0.0f} 15 | }); 16 | 17 | ::state state 18 | { 19 | .type = 0x14 | ((0x808000 + peer->punch_effect) << 8), // @note 0x8080{}14 20 | .netid = _peer[event.peer]->netid, 21 | .count = 125.0f, // @note gtnoob has this as 'waterspeed' 22 | .id = peer->state, // @note 01 ghost, 02 double jump, 04 invisible (only eyes/mouth), 08 no arms, 16 no face, 32 invisible (only legs/arms), 64 devil horns, 128 angel halo, 2048 frozen, 4096 gray skin?,8192 ducttape, 16384 Onion effect, 32768 stars effect, 65536 zombie, 131072 hit by lava, 262144 shadow effect, 524288 irradiated effect, 1048576 spotlight, 2097152 pineapple thingy 23 | .pos = { peer->pos[0] * 32, peer->pos[1] * 32 }, 24 | .speed = { 250.0f, 1000.0f } 25 | }; 26 | 27 | state_visuals(event, std::move(state)); 28 | } -------------------------------------------------------------------------------- /include/action/dialog_return/gateway_edit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "gateway_edit.hpp" 4 | 5 | void gateway_edit(ENetEvent& event, const std::vector &&pipes) 6 | { 7 | const short tilex = atoi(pipes[5zu].c_str()); 8 | const short tiley = atoi(pipes[8zu].c_str()); 9 | 10 | auto it = worlds.find(_peer[event.peer]->recent_worlds.back()); 11 | if (it == worlds.end()) return; 12 | 13 | block &block = it->second.blocks[cord(tilex, tiley)]; 14 | 15 | if (pipes[3zu] == "door_edit" || pipes[3zu] == "sign_edit") 16 | block.label = pipes[11zu]; 17 | 18 | else if (pipes[3zu] == "gateway_edit") 19 | { 20 | block.state3 &= ~(S_PUBLIC | S_LOCKED); 21 | block.state3 |= stoi(pipes[11zu]) ? S_PUBLIC : S_LOCKED; 22 | } 23 | 24 | tile_update(event, { 25 | .id = block.fg, 26 | .punch = { tilex, tiley } 27 | }, block, it->second); 28 | 29 | if (pipes[10zu] == "door_name" && pipes.size() > 12zu) 30 | { 31 | for (::door &door : it->second.doors) 32 | { 33 | if (door.pos == ::pos{tilex, tiley}) 34 | { 35 | door.dest = pipes[13]; 36 | door.id = pipes[15]; 37 | return; 38 | } 39 | } 40 | it->second.doors.emplace_back(::door( 41 | pipes[13], 42 | pipes[15], 43 | "", // @todo add password door 44 | { tilex, tiley } 45 | )); 46 | } 47 | } -------------------------------------------------------------------------------- /include/enet/unix.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file unix.h 3 | @brief ENet Unix header 4 | */ 5 | #ifndef __ENET_UNIX_H__ 6 | #define __ENET_UNIX_H__ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef MSG_MAXIOVLEN 17 | #define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN 18 | #endif 19 | 20 | typedef int ENetSocket; 21 | 22 | #define ENET_SOCKET_NULL -1 23 | 24 | #define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ 25 | #define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ 26 | 27 | #define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ 28 | #define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ 29 | 30 | typedef struct 31 | { 32 | void * data; 33 | size_t dataLength; 34 | } ENetBuffer; 35 | 36 | #define ENET_CALLBACK 37 | 38 | #define ENET_API extern 39 | 40 | typedef fd_set ENetSocketSet; 41 | 42 | #define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) 43 | #define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) 44 | #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) 45 | #define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) 46 | 47 | #endif /* __ENET_UNIX_H__ */ 48 | 49 | -------------------------------------------------------------------------------- /resources/ctx/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEMTCCAxmgAwIBAgIUBiHPF+Ggsymc8YpFicv5cnJMlj4wDQYJKoZIhvcNAQEL 3 | BQAwgaYxCzAJBgNVBAYTAklEMRAwDgYDVQQIDAdKYWthcnRhMRAwDgYDVQQHDAdK 4 | YWthcnRhMRQwEgYDVQQKDAtWZXJ0aW9uIEx0ZDEgMB4GA1UECwwXVmVydGlvbiBT 5 | ZWN0b3IgR2FtZSBEZXYxGzAZBgNVBAMMEnd3dy5ncm93dG9waWExLmNvbTEeMBwG 6 | CSqGSIb3DQEJARYPeW9ydWFraW9AZmJpLmFjMCAXDTI0MDcyOTE2MDQzNloYDzIw 7 | NTExMjE0MTYwNDM2WjCBpjELMAkGA1UEBhMCSUQxEDAOBgNVBAgMB0pha2FydGEx 8 | EDAOBgNVBAcMB0pha2FydGExFDASBgNVBAoMC1ZlcnRpb24gTHRkMSAwHgYDVQQL 9 | DBdWZXJ0aW9uIFNlY3RvciBHYW1lIERldjEbMBkGA1UEAwwSd3d3Lmdyb3d0b3Bp 10 | YTEuY29tMR4wHAYJKoZIhvcNAQkBFg95b3J1YWtpb0BmYmkuYWMwggEiMA0GCSqG 11 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0aPAePSUlIorLmSkal7NjsCACp6JgbHaS 12 | 5l9UWSFsdv9YB77ZNE/xOFQKJXgfT3wxDdXfXj359vDSbOJh6kWw4qxzmiY/A2gm 13 | t5sdJBl+nEfCZMUckSNExi2tI8CIh96X1qetdg8ALKbIq098mJwmYzLN4E0cIf/n 14 | CbCwSXTtz0bOX/eEKlHOZyVKgsrrUPm0Q5jT3eNJss9nN8Xk30nPs9fAPs2GO/G4 15 | AKIWsqHdP5UumbW7DmTbQKa5NNux7u+fDy+yU4kqwWMD3Mhz3AfOSEuYtvS9/Mgz 16 | AKg4J5j6Vjq+J/xR3xjhN6ztjbl1/4fgfhVxxJvnMw+D03Nhf21PAgMBAAGjUzBR 17 | MB0GA1UdDgQWBBSzTMmvaR4u9UKkf0NpF5LKSvvqXDAfBgNVHSMEGDAWgBSzTMmv 18 | aR4u9UKkf0NpF5LKSvvqXDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA 19 | A4IBAQCWrEZIKhNNjx0843ujsxXsRBA3qzG7FjhQ8+2gSt4TFnh5STIEbF34/DbF 20 | 22HBxrZy+jW0lXseJTOI/RH2qcDHpOMKoEC5I5SAiXd1wjOR6Yy7a/fvrxglbkcc 21 | YCZig7gqax18U8HF/sk6apcIaEpKuMohZ1ZF4KiEJgm07RoCcGNjrg6Ch5ectFxB 22 | 6JR/8fRZ42s/pgP2IOsZ64XMY/Xcm5DWsEOGD/80NEiAhlWAN/JELv+johcUvXLa 23 | 7uAfZ88c42eDL1zkD0yCmx5tOXgoS7OxJTCyL1AVcFSLu1ioMsySJ0hiQ95os+kQ 24 | s3UKdSJjmu0BR3S1tNiwgf1BYd/z 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /include/action/quit_to_exit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/RequestWorldSelectMenu.hpp" 3 | #include "quit_to_exit.hpp" 4 | 5 | void action::quit_to_exit(ENetEvent& event, const std::string& header, bool skip_selection = false) 6 | { 7 | auto &peer = _peer[event.peer]; 8 | 9 | auto it = worlds.find(peer->recent_worlds.back()); 10 | if (it == worlds.end()) return; // @note peer was not in a world, therefore nothing to exit from. 11 | 12 | packet::create(*event.peer, true, 0, { "OnSetPos", std::vector{-1, -1} }); 13 | 14 | if (--it->second.visitors <= 0) worlds.erase(it); // @note take 1, and if result is 0, delete memory copy of world. 15 | 16 | peer->netid = 0; // this will fix any packets being sent outside of world; this can also be used to check if peer is not in a world. 17 | 18 | std::string &prefix = peer->prefix; 19 | const char* message = std::format("`5<`{}{}`` left, `w{}`` others here>``", prefix, peer->ltoken[0], it->second.visitors).c_str(); 20 | const char* netid = std::format("netID|{}\n", peer->netid).c_str(); 21 | const char* pId = std::format("pId|{}\n", peer->user_id).c_str(); // @note this is found during OnSpawn 'eid', the value is the same for user_id. 22 | peers(event, PEER_SAME_WORLD, [&peer, message, netid, pId](ENetPeer& p) 23 | { 24 | packet::create(p, false, 0, { "OnConsoleMessage", message }); 25 | packet::create(p, false, 0, { "OnRemove", netid, pId }); // @todo 26 | }); 27 | 28 | if (prefix == "2" || prefix == "c") prefix.front() = 'w'; 29 | if (!skip_selection) on::RequestWorldSelectMenu(event); 30 | } -------------------------------------------------------------------------------- /include/action/dialog_return/socialportal.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "socialportal.hpp" 3 | 4 | void socialportal(ENetEvent& event, const std::vector &&pipes) 5 | { 6 | auto &peer = _peer[event.peer]; 7 | 8 | /* buttonClicked */ 9 | if (pipes[5zu] == "showfriend") 10 | { 11 | /* temp data */ 12 | u_char __online{}; 13 | 14 | // @todo i will improve!! cause i hate this so much t-t 15 | for (const ::Friend &Friend : peer->friends) 16 | peers(event, PEER_ALL, [&Friend, &__online](ENetPeer& peer){ 17 | auto &p = _peer[&peer]; 18 | if (p->ltoken[0] == Friend.name) 19 | ++__online; 20 | }); 21 | 22 | packet::create(*event.peer, false, 0, { 23 | "OnDialogRequest", 24 | std::format( 25 | "set_default_color|`o\n" 26 | "add_label_with_icon|big|0 of {} `wFriends Online``|left|1366|\n" 27 | "add_spacer|small|\n" 28 | "add_textbox|`oNone of your friends are currently online.``|left|\n" 29 | "add_spacer|small|\n" 30 | "add_spacer|small|\n" 31 | "add_button|friend_all|Show offline and ignored too|noflags|0|0|\n" 32 | "add_button|all_friends|Edit Friends|noflags|0|0|\n" 33 | "add_button|friends_options|Friend Options|noflags|0|0|\n" 34 | "add_button|back|Back|noflags|0|0|\n" 35 | "add_button||Close|noflags|0|0|\n" 36 | "end_dialog|friends|||\n" 37 | "add_quick_exit|\n", 38 | __online 39 | ).c_str() 40 | }); 41 | } 42 | } -------------------------------------------------------------------------------- /include/https/server_data.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "server_data.hpp" 4 | 5 | ::server_data init_server_data() 6 | { 7 | ::server_data server_data{}; 8 | { 9 | std::ifstream file("server_data.php"); 10 | if (!file.is_open()) 11 | { 12 | std::ofstream write("server_data.php"); 13 | write << 14 | std::format( 15 | "server|{}\n" 16 | "port|{}\n" 17 | "type|{}\n" 18 | "type2|{}\n" 19 | "#maint|{}\n" 20 | "loginurl|{}\n" 21 | "meta|{}\n" 22 | "RTENDMARKERBS1001", 23 | server_data.server, server_data.port, server_data.type, server_data.type2, server_data.maint, server_data.loginurl, server_data.meta 24 | ); 25 | } // @note close write 26 | else 27 | { 28 | std::vector pipes; 29 | for (std::string line; std::getline(file, line); ) 30 | { 31 | auto pipe_pair = readch(line, '|'); 32 | pipes.insert(pipes.end(), pipe_pair.begin(), pipe_pair.end()); 33 | } 34 | 35 | server_data.server = pipes[1]; 36 | server_data.port = std::stoi(pipes[3]); 37 | server_data.type = std::stoi(pipes[5]); 38 | server_data.type2 = std::stoi(pipes[7]); 39 | server_data.maint = pipes[9]; 40 | server_data.loginurl = pipes[11]; 41 | server_data.meta = pipes[13]; 42 | } // @note delete str, pipes 43 | } // @note close file 44 | return server_data; 45 | } -------------------------------------------------------------------------------- /include/state/item_activate.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/SetClothing.hpp" 3 | #include "commands/punch.hpp" 4 | #include "item_activate.hpp" 5 | 6 | void item_activate(ENetEvent& event, state state) 7 | { 8 | auto &peer = _peer[event.peer]; 9 | 10 | ::item &item = items[state.id]; 11 | if (item.cloth_type != clothing::none) 12 | { 13 | float &cloth_type = peer->clothing[item.cloth_type]; 14 | 15 | cloth_type = (cloth_type == state.id) ? 0 : state.id; 16 | peer->punch_effect = get_punch_id(state.id); // @todo 17 | 18 | packet::create(*event.peer, true, 0, { "OnEquipNewItem", state.id }); 19 | on::SetClothing(event); // @todo 20 | } 21 | else 22 | { 23 | if (state.id == 242 || state.id == 1796) 24 | { 25 | auto lock = std::ranges::find_if(peer->slots, [&state](::slot &slot) { return slot.id == state.id; }); 26 | if (lock == peer->slots.end()) return; 27 | 28 | if (lock->id == 242 && lock->count >= 100) 29 | { 30 | short nokori = peer->emplace(slot(1796, 1)); 31 | if (nokori == 0) peer->emplace(slot(lock->id, -100)); // @note do not take 100 if dl is already at 200. 32 | } 33 | else if (lock->id == 1796 && lock->count >= 1) 34 | { 35 | short nokori = peer->emplace(slot(242, 100)); 36 | short hyaku = 100 - nokori; 37 | if (hyaku == 100) peer->emplace(slot(1796, -1)); // @note do not take 1 if cannot take 100 more wls 38 | else peer->emplace(slot(242, -hyaku)); // @note return wls if not 100 39 | } 40 | inventory_visuals(event); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /include/tools/create_dialog.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TOOLS_CREATE_DIALOG_HPP 3 | #define TOOLS_CREATE_DIALOG_HPP 4 | 5 | class create_dialog 6 | { 7 | std::string _d{}; 8 | 9 | public: 10 | create_dialog& set_default_color(std::string code); 11 | create_dialog& add_label(std::string size, std::string label); 12 | create_dialog& add_label_with_icon(std::string size, std::string label, int icon); 13 | create_dialog& add_label_with_ele_icon(std::string size, std::string label, int icon, u_char element); 14 | create_dialog& add_textbox(std::string label); 15 | create_dialog& add_text_input(std::string id, std::string label, short set_value, short length); 16 | create_dialog& add_text_input(std::string id, std::string label, std::string set_value, short length); 17 | create_dialog& embed_data(std::string id, std::string data); 18 | create_dialog& embed_data(std::string id, int data); 19 | create_dialog& add_spacer(std::string size); 20 | create_dialog& set_custom_spacing(short x, short y); 21 | create_dialog& add_button(std::string btn_id, std::string btn_name); 22 | create_dialog& add_custom_button(std::string btn_id, std::string image); 23 | create_dialog& add_custom_label(std::string label, std::string pos); 24 | create_dialog& add_custom_break(); 25 | create_dialog& add_custom_margin(short x, short y); 26 | create_dialog& add_achieve(std::string total); 27 | create_dialog& add_quick_exit(); 28 | create_dialog& add_popup_name(std::string popup_name); 29 | create_dialog& add_player_info(std::string label, std::string progress_bar_name, int progress, int total_progress); 30 | 31 | std::string end_dialog(std::string btn_id, std::string btn_close = "Cancel", std::string btn_return = "OK"); 32 | }; 33 | 34 | #endif -------------------------------------------------------------------------------- /include/action/dialog_return/__dialog_return.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "popup.hpp" 4 | #include "drop_item.hpp" 5 | #include "trash_item.hpp" 6 | #include "find_item.hpp" 7 | #include "gateway_edit.hpp" 8 | #include "billboard_edit.hpp" 9 | #include "lock_edit.hpp" 10 | #include "create_blast.hpp" 11 | #include "socialportal.hpp" 12 | #include "peer_edit.hpp" 13 | #include "megaphone.hpp" 14 | 15 | #include "__dialog_return.hpp" 16 | 17 | std::unordered_map &&)>> dialog_return_pool 18 | { 19 | {"popup", std::bind(&popup, std::placeholders::_1, std::placeholders::_2)}, 20 | 21 | {"drop_item", std::bind(&drop_item, std::placeholders::_1, std::placeholders::_2)}, 22 | {"trash_item", std::bind(&trash_item, std::placeholders::_1, std::placeholders::_2)}, 23 | {"find_item", std::bind(&find_item, std::placeholders::_1, std::placeholders::_2)}, 24 | 25 | {"gateway_edit", std::bind(&gateway_edit, std::placeholders::_1, std::placeholders::_2)}, 26 | {"door_edit", std::bind(&gateway_edit, std::placeholders::_1, std::placeholders::_2)}, 27 | {"sign_edit", std::bind(&gateway_edit, std::placeholders::_1, std::placeholders::_2)}, 28 | 29 | {"billboard_edit", std::bind(&billboard_edit, std::placeholders::_1, std::placeholders::_2)}, 30 | {"lock_edit", std::bind(&lock_edit, std::placeholders::_1, std::placeholders::_2)}, 31 | {"peer_edit", std::bind(&peer_edit, std::placeholders::_1, std::placeholders::_2)}, 32 | 33 | {"create_blast", std::bind(&create_blast, std::placeholders::_1, std::placeholders::_2)}, 34 | {"socialportal", std::bind(&socialportal, std::placeholders::_1, std::placeholders::_2)}, 35 | {"megaphone", std::bind(&megaphone, std::placeholders::_1, std::placeholders::_2)}, 36 | }; -------------------------------------------------------------------------------- /resources/ctx/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC0aPAePSUlIorL 3 | mSkal7NjsCACp6JgbHaS5l9UWSFsdv9YB77ZNE/xOFQKJXgfT3wxDdXfXj359vDS 4 | bOJh6kWw4qxzmiY/A2gmt5sdJBl+nEfCZMUckSNExi2tI8CIh96X1qetdg8ALKbI 5 | q098mJwmYzLN4E0cIf/nCbCwSXTtz0bOX/eEKlHOZyVKgsrrUPm0Q5jT3eNJss9n 6 | N8Xk30nPs9fAPs2GO/G4AKIWsqHdP5UumbW7DmTbQKa5NNux7u+fDy+yU4kqwWMD 7 | 3Mhz3AfOSEuYtvS9/MgzAKg4J5j6Vjq+J/xR3xjhN6ztjbl1/4fgfhVxxJvnMw+D 8 | 03Nhf21PAgMBAAECggEAGbDB1MSHSBj5o9GNKWTF3mHDxS0C8fEwF24n0BabLFtr 9 | tCjyM/L/mU2YphM83lSOzlt2g8bjU3enRofL2v6l6vD0dsfSP3HoQG8v7v/ng4CU 10 | tWltKkq+t3nzIi8vqSGUAJJIMWrY6wDwxS2j9Y2z2sGQiAGzaVisHMXj+86SEJUQ 11 | PVUyhvovVEEXvgbyAsHfYTicqCUEf3hY35CNusgn2ykot9uLC0JODCOZoQV338Eb 12 | M0Wr0Mi3SFJkwOQuSDTjcOZ9KnXVK3Kl+JFUD51cWPINy1R9g+tavtrL/OeYAJmQ 13 | hMXG073PwwxYpiiwq7WjIfljb8eLlP9ZunCUnaYmAQKBgQD7b1ic1Th/TqnLYiFH 14 | ZSVWWdOdGSs02o2iXa2ZzVnMhGO9PcpsW3NmL+z/dFhNz5DlohPw20Kc9Q8rmyLJ 15 | idYza1mnwH94hyilSEIfo/4SFH+MK8vdESK+z5xNuEL1YhK61DvNVnaO7xMJmKPw 16 | BIZnYSPDigUTm7EYKrvTpNbaAQKBgQC3r3jQEdPfdjklwhF/FqOeHIMbKH/jkYG/ 17 | Bw8p2Ng+uqQrUwhtbyjKxnps+czekvFbqw6JpuAzkJ4NA+c4Cr2h+FKnc1gPO3y4 18 | +zjgxdfYAnAcjpUEp34VV6oBVFucJFadp0jXwDxf8+xUlz7v/JFBwSjErAuIqgJn 19 | 4DWCL/wnTwKBgHMoTC2IepfUL3A3QYaxjKg/++u321IZx0TWIuyOYNKK0COcaVm3 20 | iOMEkEdvwgHhTzvdP8TQp3G7y3btVsF3n+NtB2MNh1RskvEgZyiWs4cUXFaWuIhH 21 | kOJTtALkocZBZNKs4bbqIuLUHKQIhQ0pBWXT1813KVwRssqex+fnV4ABAoGAckqi 22 | d4TAOkjLYi0Qye0CPX0sLpfSi3ycKIpx6u3cD5v+Tl7J3Z3O2e0JfAkqakswFoOm 23 | 9gt5cVxIm3yUQBCe0cs7Uqm4XzH6dvcJ+wHfPa62p24oVs8I6qqzQ0SEA/GwW0Qd 24 | VPFuH54crL23EYgrsahIf6c1PgHaoVumr6y/zo0CgYAYIH/rjZwvB4X54x3U1+m3 25 | wNXI4U0k3ebe2sHUaTcrIW20aMV0MS0nIqJEImPDaUzYQXWALyCdNjg7MnbrkzOe 26 | AkmOh6Gg3bkykNGtchc0oVxl8rPqR02jDHPMP+Vp4uWFgiHoHjb4reConNFfyFPQ 27 | zzkfV5CsiV/lRUdligDE6Q== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /include/enet/win32.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file win32.h 3 | @brief ENet Win32 header 4 | */ 5 | #ifndef __ENET_WIN32_H__ 6 | #define __ENET_WIN32_H__ 7 | 8 | #ifdef _MSC_VER 9 | #ifdef ENET_BUILDING_LIB 10 | #pragma warning (disable: 4267) // size_t to int conversion 11 | #pragma warning (disable: 4244) // 64bit to 32bit int 12 | #pragma warning (disable: 4018) // signed/unsigned mismatch 13 | #pragma warning (disable: 4146) // unary minus operator applied to unsigned type 14 | #ifndef _CRT_SECURE_NO_DEPRECATE 15 | #define _CRT_SECURE_NO_DEPRECATE 16 | #endif 17 | #ifndef _CRT_SECURE_NO_WARNINGS 18 | #define _CRT_SECURE_NO_WARNINGS 19 | #endif 20 | #endif 21 | #endif 22 | 23 | #include 24 | #include 25 | 26 | typedef SOCKET ENetSocket; 27 | 28 | #define ENET_SOCKET_NULL INVALID_SOCKET 29 | 30 | #define ENET_HOST_TO_NET_16(value) (htons (value)) 31 | #define ENET_HOST_TO_NET_32(value) (htonl (value)) 32 | 33 | #define ENET_NET_TO_HOST_16(value) (ntohs (value)) 34 | #define ENET_NET_TO_HOST_32(value) (ntohl (value)) 35 | 36 | typedef struct 37 | { 38 | size_t dataLength; 39 | void * data; 40 | } ENetBuffer; 41 | 42 | #define ENET_CALLBACK __cdecl 43 | 44 | #ifdef ENET_DLL 45 | #ifdef ENET_BUILDING_LIB 46 | #define ENET_API __declspec( dllexport ) 47 | #else 48 | #define ENET_API __declspec( dllimport ) 49 | #endif /* ENET_BUILDING_LIB */ 50 | #else /* !ENET_DLL */ 51 | #define ENET_API extern 52 | #endif /* ENET_DLL */ 53 | 54 | typedef fd_set ENetSocketSet; 55 | 56 | #define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) 57 | #define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) 58 | #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) 59 | #define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) 60 | 61 | #endif /* __ENET_WIN32_H__ */ 62 | 63 | 64 | -------------------------------------------------------------------------------- /include/commands/edit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "action/wrench.hpp" 3 | #include "edit.hpp" 4 | 5 | void edit(ENetEvent& event, const std::string_view text) 6 | { 7 | if (text.length() <= sizeof("edit ") - 1) 8 | { 9 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "Usage: /edit `w{player name}``" }); 10 | return; 11 | } 12 | std::string name{ text.substr(sizeof("edit ")-1) }; 13 | 14 | u_char is_online{}; 15 | std::string fmt = 16 | "set_default_color|`o\n" 17 | "add_label|big|Username: `w{0}`` (`s{1}``)|left\n" 18 | "embed_data|name|{0}\n" 19 | "add_spacer|small|\n" 20 | "add_text_input|role|Role: |{2}|3|\n" 21 | "add_text_input|level|Level: |{3}|3|\n" 22 | "add_text_input|gems|Gems: |{4}|10|\n" 23 | "add_spacer|small|\n" 24 | "embed_data|status|{5}\n" 25 | "end_dialog|peer_edit|Close|`2Edit|\n"; 26 | 27 | peers(event, PEER_ALL, [&event, name, &is_online, fmt](ENetPeer& p) 28 | { 29 | auto &peer = _peer[&p]; 30 | if (_peer[&p]->ltoken[0] == name) 31 | { 32 | auto &peer = _peer[&p]; 33 | is_online = 1; 34 | packet::create(*event.peer, false, 0, { 35 | "OnDialogRequest", 36 | std::vformat(fmt, std::make_format_args(name, "`2Online", peer->role, peer->level.front(), peer->gems, is_online)).c_str() 37 | }); 38 | return; 39 | } 40 | }); 41 | if (!is_online) 42 | { 43 | peer &offline = ::peer().read(name); 44 | 45 | packet::create(*event.peer, false, 0, { 46 | "OnDialogRequest", 47 | std::vformat(fmt, std::make_format_args(name, "`sOffline", offline.role, offline.level.front(), offline.gems, is_online)).c_str() 48 | }); 49 | } 50 | } -------------------------------------------------------------------------------- /include/on/RequestWorldSelectMenu.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "RequestWorldSelectMenu.hpp" 3 | 4 | void on::RequestWorldSelectMenu(ENetEvent& event) 5 | { 6 | auto &peer = _peer[event.peer]; 7 | 8 | auto section = [&peer](const auto& range, const char* color) 9 | { 10 | std::string result; 11 | for (const auto &name : range) 12 | if (!name.empty()) 13 | { 14 | auto it = worlds.find(name); // @todo reduce iteration. 15 | result.append((it != worlds.end()) ? 16 | std::format("add_floater|{}|{}|0.5|{}\n", name, it->second.visitors, color) : 17 | std::format("add_floater|{}|0|0.5|{}\n", name, color)); 18 | } 19 | return result; 20 | }; 21 | 22 | std::vector popular_names{}; 23 | for (const auto &world : worlds) 24 | if (world.second.visitors > 0) popular_names.emplace_back(world.first); // @todo only fetch top 10 worlds, instead of all the worlds with people. 25 | 26 | packet::create(*event.peer, false, 0, { 27 | "OnRequestWorldSelectMenu", 28 | std::format( 29 | "add_filter|\n" 30 | "add_heading|Top Worlds|\n{}{}" 31 | "add_heading|My Worlds|\n{}" 32 | "add_heading|Recently Visited Worlds|\n{}", 33 | "add_floater|wotd_world|\u013B WOTD|0|0.5|3529161471\n", 34 | section(popular_names, "3529161471"), 35 | section(peer->my_worlds, "2147418367"), 36 | section(peer->recent_worlds, "3417414143") 37 | ).c_str(), 38 | 0 39 | }); 40 | packet::create(*event.peer, false, 0, { 41 | "OnConsoleMessage", 42 | std::format("Where would you like to go? (`w{}`` online)", peers(event).size()).c_str() 43 | }); 44 | } -------------------------------------------------------------------------------- /include/tools/string.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | 4 | std::vector readch(const std::string &str, char c) 5 | { 6 | std::vector result; 7 | result.reserve(std::ranges::count(str, c) + 1); 8 | 9 | for (auto &&part : std::views::split(str, c)) 10 | result.emplace_back(std::ranges::begin(part), std::ranges::end(part)); 11 | 12 | return result; 13 | } 14 | 15 | bool alpha(const std::string& str) 16 | { 17 | return !str.empty() && std::ranges::all_of(str, ::isalpha); 18 | } 19 | 20 | bool number(const std::string& str) 21 | { 22 | return !str.empty() && std::ranges::all_of(str, ::isdigit); 23 | } 24 | 25 | bool alnum(const std::string& str) 26 | { 27 | return !str.empty() && std::ranges::all_of(str, ::isalnum); 28 | } 29 | 30 | #include 31 | #include 32 | 33 | std::string base64_decode(const std::string& encoded) 34 | { 35 | try 36 | { 37 | BIO *bio = BIO_new_mem_buf(encoded.data(), static_cast(encoded.size())); 38 | BIO *base64 = BIO_new(BIO_f_base64()); 39 | 40 | bio = BIO_push(base64, bio); 41 | BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); 42 | 43 | std::vector buf(encoded.size()); 44 | int bio_read = BIO_read(bio, buf.data(), static_cast(buf.size())); 45 | BIO_free_all(bio); 46 | 47 | return std::string{ buf.data(), static_cast(bio_read) }; 48 | } 49 | catch (...){} // @note what(): basic_string::_M_create 50 | return ""; 51 | } 52 | 53 | std::size_t fnv1a(const std::string& value) noexcept { 54 | constexpr std::size_t offset = 14695981039346656037zu; 55 | constexpr std::size_t prime = 1099511628211zu; 56 | 57 | std::size_t fnv1a = offset; 58 | for (u_char c : value) 59 | { 60 | fnv1a ^= c; 61 | fnv1a *= prime; 62 | } 63 | return fnv1a; 64 | } -------------------------------------------------------------------------------- /include/commands/__command.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/Action.hpp" 3 | #include "find.hpp" 4 | #include "warp.hpp" 5 | #include "edit.hpp" 6 | #include "punch.hpp" 7 | #include "skin.hpp" 8 | #include "sb.hpp" 9 | #include "who.hpp" 10 | #include "me.hpp" 11 | #include "weather.hpp" 12 | #include "ghost.hpp" 13 | #include "ageworld.hpp" 14 | #include "__command.hpp" 15 | 16 | /* if you plan to use this outside of this file, please include in __command.hpp (^-^) - and just make it a void. */ 17 | auto help_return = [](ENetEvent& event, const std::string_view text) 18 | { 19 | packet::action(*event.peer, "log", "msg|>> Commands: /find /warp {world} /edit {player} /punch {id} /skin {id} /sb {msg} /who /me {msg} /weather {id} /ghost /ageworld /wave /dance /love /sleep /facepalm /fp /smh /yes /no /omg /idk /shrug /furious /rolleyes /foldarms /stubborn /fold /dab /sassy /dance2 /march /grumpy /shy"); 20 | }; 21 | 22 | std::unordered_map> cmd_pool 23 | { 24 | {"help", help_return }, 25 | {"?", help_return }, 26 | {"find", &find}, 27 | {"warp", &warp}, 28 | {"edit", &edit}, 29 | {"punch", &punch}, 30 | {"skin", &skin}, 31 | {"sb", &sb}, 32 | {"who", &who}, 33 | {"me", &me}, 34 | {"weather", &weather}, 35 | {"ghost", &ghost}, 36 | {"ageworld", &ageworld}, 37 | {"wave", &on::Action}, {"dance", &on::Action}, {"love", &on::Action}, {"sleep", &on::Action}, {"facepalm", &on::Action}, {"fp", &on::Action}, 38 | {"smh", &on::Action}, {"yes", &on::Action}, {"no", &on::Action}, {"omg", &on::Action}, {"idk", &on::Action}, {"shrug", &on::Action}, 39 | {"furious", &on::Action}, {"rolleyes", &on::Action}, {"foldarms", &on::Action}, {"fa", &on::Action}, {"stubborn", &on::Action}, {"fold", &on::Action}, 40 | {"dab", &on::Action}, {"sassy", &on::Action}, {"dance2", &on::Action}, {"march", &on::Action}, {"grumpy", &on::Action}, {"shy", &on::Action} 41 | }; -------------------------------------------------------------------------------- /include/on/EmoticonDataChanged.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "EmoticonDataChanged.hpp" 3 | 4 | std::unordered_map emoticon = 5 | { 6 | {"wl", "\u0101"}, {"yes", "\u0102"}, {"no", "\u0103"}, {"love", "\u0104"}, {"oops", "\u0105"}, {"shy", "\u0106"}, 7 | {"wink", "\u0107"}, {"tongue", "\u0108"}, {"agree", "\u0109"}, {"sleep", "\u010A"}, {"punch", "\u010B"}, {"music", "\u010C"}, 8 | {"build", "\u010D"}, {"megaphone", "\u010E"}, {"sigh", "\u010F"}, {"mad", "\u0110"}, {"wow", "\u0111"}, {"dance", "\u0112"}, 9 | {"see-no-evil", "\u0113"}, {"bheart", "\u0114"}, {"heart", "\u0115"}, {"grow", "\u0116"}, {"gems", "\u0117"}, {"kiss", "\u0118"}, 10 | {"gtoken", "\u0119"}, {"lol", "\u011A"}, {"smile", "\u011B"}, {"cool", "\u011C"}, {"cry", "\u011D"}, {"vend", "\u011E"}, 11 | {"bunny", "\u011F"}, {"cactus", "\u0120"}, {"pine", "\u0121"}, {"peace", "\u0122"}, {"terror", "\u0123"}, {"troll", "\u0124"}, 12 | {"evil", "\u0125"}, {"fireworks", "\u0126"}, {"football", "\u0127"}, {"alien", "\u0128"}, {"party", "\u0129"}, {"pizza", "\u012A"}, 13 | {"clap", "\u012B"}, {"song", "\u012C"}, {"ghost", "\u012D"}, {"nuke", "\u012E"}, {"halo", "\u012F"}, {"turkey", "\u0130"}, 14 | {"gift", "\u0131"}, {"cake", "\u0132"}, {"heartarrow", "\u0133"}, {"lucky", "\u0134"}, {"shamrock", "\u0135"}, {"grin", "\u0136"}, 15 | {"ill", "\u0137"}, {"eyes", "\u0138"}, {"weary", "\u0139"}, {"moyai", "\u013A"}, {"plead", "\u013B"} 16 | }; 17 | 18 | void on::EmoticonDataChanged(ENetEvent& event) 19 | { 20 | std::string EmoticonData; 21 | EmoticonData.reserve(emoticon.size() * 23/* emoticon data + ()||1/0& */); 22 | for (const auto &[key, value] : emoticon) 23 | EmoticonData.append(std::format("({})|{}|1&", key, value)); // @todo add requirements for unlocking emoticons 24 | packet::create(*event.peer, false, 0, { 25 | "OnEmoticonDataChanged", 26 | 201560520, 27 | EmoticonData.c_str() 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /include/event_type/receive.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "action/__action.hpp" 3 | #include "state/__states.hpp" 4 | #include "tools/string.hpp" 5 | #include "receive.hpp" 6 | 7 | void receive(ENetEvent& event) 8 | { 9 | std::span data{event.packet->data, event.packet->dataLength}; 10 | switch (data[0zu]) 11 | { 12 | case 2: case 3: 13 | { 14 | std::string header{data.begin() + 4, data.end() - 1}; 15 | puts(header.c_str()); 16 | 17 | std::ranges::replace(header, '\n', '|'); 18 | std::vector pipes = readch(header, '|'); 19 | 20 | const std::string action = (pipes[0zu] == "protocol") ? pipes[0zu] : std::format("{}|{}", pipes[0zu], pipes[1zu]); 21 | if (const auto i = action_pool.find(action); i != action_pool.end()) 22 | i->second(event, header); 23 | break; 24 | } 25 | case 4: 26 | { 27 | state state{}; 28 | { 29 | std::vector raw_state{event.packet->dataLength - 4}; 30 | { 31 | std::size_t size = raw_state.size(); 32 | if ((size + 4zu) >= 61zu) // @note growtopia packets are 61 (::state), however most are greater than 61 (visuals, ect) 33 | { 34 | std::byte *_1bit = reinterpret_cast(event.packet->data) + 4; // @note ignore 04 00 00 00 35 | for (std::size_t i = 0zu; i < size; ++i) 36 | raw_state[i] = _1bit[i]; 37 | } 38 | } // @note deletes size 39 | state = get_state(std::move(raw_state)); 40 | } // @note deletes raw_state 41 | if (const auto i = state_pool.find(state.type); i != state_pool.end()) 42 | i->second(event, std::move(state)); 43 | break; 44 | } 45 | } 46 | enet_packet_destroy(event.packet); 47 | } -------------------------------------------------------------------------------- /include/state/tile_activate.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "action/join_request.hpp" 3 | #include "action/quit_to_exit.hpp" 4 | #include "tile_activate.hpp" 5 | 6 | void tile_activate(ENetEvent& event, state state) 7 | { 8 | auto &peer = _peer[event.peer]; 9 | 10 | if (!worlds.contains(peer->recent_worlds.back())) return; 11 | ::world &world = worlds.at(peer->recent_worlds.back()); 12 | 13 | ::block &block = world.blocks[cord(state.punch.x, state.punch.y)]; 14 | ::item &item = items[block.fg]; // @todo handle bg 15 | 16 | switch (item.type) 17 | { 18 | case type::MAIN_DOOR: 19 | { 20 | action::quit_to_exit(event, "", false); 21 | break; 22 | } 23 | case type::DOOR: // @todo add door-to-door with door::id 24 | case type::PORTAL: 25 | { 26 | bool has_dest{}; 27 | for (::door &door : world.doors) 28 | { 29 | if (door.pos == state.punch) 30 | { 31 | has_dest = true; 32 | const std::string_view dest{ door.dest }; 33 | 34 | action::quit_to_exit(event, "", true); 35 | action::join_request(event, "", dest); 36 | break; 37 | } 38 | } 39 | if (!has_dest) 40 | { 41 | packet::create(*event.peer, true, 0, { 42 | "OnSetPos", 43 | std::vector{peer->rest_pos.front(), peer->rest_pos.back()} 44 | }); 45 | packet::create(*event.peer, false, 0, { 46 | "OnZoomCamera", 47 | std::vector{10000.0f}, // @todo 48 | 1000u 49 | }); 50 | packet::create(*event.peer, true, 0, { "OnSetFreezeState", 0u }); 51 | packet::create(*event.peer, true, 0, { "OnPlayPositioned", "audio/teleport.wav" }); 52 | } 53 | break; 54 | } 55 | } 56 | 57 | state_visuals(event, std::move(state)); // finished. 58 | } -------------------------------------------------------------------------------- /include/action/enter_game.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "on/RequestWorldSelectMenu.hpp" 3 | #include "tools/string.hpp" 4 | #include "on/SetBux.hpp" 5 | #include "enter_game.hpp" 6 | 7 | void action::enter_game(ENetEvent& event, const std::string& header) 8 | { 9 | auto &peer = _peer[event.peer]; 10 | 11 | peer->user_id = fnv1a(peer->ltoken[0]); // @note this is to proeprly downgrade std::hash to integer size hash (Growtopia Standards) 12 | peer->prefix = (peer->role == MODERATOR) ? "#@" : (peer->role == DEVELOPER) ? "8@" : peer->prefix; 13 | 14 | if (peer->slots.size() <= 2) // @note growpedia acts as the 3rd slot; meaning if a peer only has 2 slots they are new player. 15 | { 16 | peer->emplace({6336, 1}); // @note growpedia | cannot trash/drop 17 | peer->emplace({9640, 1}); // @note My First World Lock 18 | } 19 | 20 | on::RequestWorldSelectMenu(event); 21 | packet::create(*event.peer, false, 0, { 22 | "OnConsoleMessage", 23 | std::format("Welcome back, `{}{}````. No friends are online.", 24 | peer->prefix, peer->ltoken[0]).c_str() 25 | }); 26 | packet::create(*event.peer, false, 0, {"OnConsoleMessage", "`5Personal Settings active:`` `#Can customize profile``"}); 27 | packet::create(*event.peer, false, 0, { 28 | "UpdateMainMenuTheme", 29 | 0, 30 | 4226000383u, 31 | 4226000383u, 32 | "4226000383|4226000383|80543231|80543231|1554912511|1554912511" 33 | }); 34 | on::SetBux(event); 35 | packet::create(*event.peer, false, 0, {"SetHasGrowID", 1, peer->ltoken[0].c_str(), ""}); 36 | 37 | { 38 | std::time_t now = std::time(nullptr); 39 | std::tm time = *std::localtime(&now); 40 | 41 | packet::create(*event.peer, false, 0, { 42 | "OnTodaysDate", 43 | time.tm_mon + 1, 44 | time.tm_mday, 45 | 0u, // @todo 46 | 0u // @todo 47 | }); 48 | } // @note delete now, time 49 | 50 | ::state state{ 51 | .type = 0x16 // @noote PACKET_PING_REQUEST 52 | }; 53 | send_data(*event.peer, compress_state(state)); 54 | } -------------------------------------------------------------------------------- /include/action/info.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "tools/create_dialog.hpp" 4 | #include "info.hpp" 5 | 6 | std::vector properties(std::byte property) 7 | { 8 | std::vector temp{}; 9 | 10 | u_char _property = std::to_integer(property); 11 | if (_property == 14) temp.emplace_back("`oA lock makes it so only you (and designated friends) can edit an area.``"); 12 | 13 | if (_property & 01) temp.emplace_back("`1This item can be placed in two directions, depending on the direction you're facing.``"); 14 | if (_property & 02) temp.emplace_back("`1This item has special properties you can adjust with the Wrench.``"); 15 | if (_property & 04) temp.emplace_back("`1This item never drops any seeds.``"); 16 | if (_property & 0x08) temp.emplace_back("`1This item can't be destroyed - smashing it will return it to your backpack if you have room!``"); 17 | if (_property & 0x10) temp.emplace_back("`1This item can be transmuted.``"); 18 | if (_property & 0x90) temp.emplace_back("`1This item can only be used in World-Locked worlds.``"); 19 | 20 | return temp; 21 | } 22 | 23 | void action::info(ENetEvent& event, const std::string& header) 24 | { 25 | std::string itemID = readch(header, '|')[4]; 26 | 27 | item &item = items[atoi(itemID.c_str())]; 28 | 29 | ::create_dialog create_dialog = 30 | ::create_dialog() 31 | .set_default_color("`o") 32 | .add_label_with_ele_icon("big", std::format("`wAbout {}``", item.raw_name), item.id, 0) 33 | .add_spacer("small") 34 | .add_textbox(item.info) 35 | .add_spacer("small"); 36 | 37 | if (item.rarity < 999) 38 | create_dialog 39 | .add_textbox(std::format("Rarity: `w{}``", item.rarity)) 40 | .add_spacer("small"); 41 | 42 | for (const std::string &prop : properties(item.property)) 43 | create_dialog.add_textbox(prop); 44 | 45 | packet::create(*event.peer, false, 0, 46 | { 47 | "OnDialogRequest", 48 | create_dialog 49 | .add_spacer("small") 50 | .embed_data("itemID", item.id) 51 | .end_dialog("continue", "", "OK").c_str() 52 | }); 53 | } -------------------------------------------------------------------------------- /include/action/logging_in.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "join_request.hpp" 4 | #include "logging_in.hpp" 5 | 6 | void action::logging_in(ENetEvent& event, const std::string& header) 7 | { 8 | auto &peer = _peer[event.peer]; 9 | 10 | try 11 | { 12 | std::vector pipes = readch(header, '|'); 13 | if (pipes.size() < 4zu) throw std::runtime_error(""); 14 | 15 | if (pipes[2zu] == "ltoken") 16 | { 17 | const std::string decoded = base64_decode(pipes[3zu]); 18 | if (decoded.empty()) throw std::runtime_error(""); 19 | 20 | if (std::size_t pos = decoded.find("growId="); pos != std::string::npos) 21 | { 22 | pos += sizeof("growId=")-1zu; 23 | peer->ltoken[0] = decoded.substr(pos, decoded.find('&', pos) - pos); 24 | } 25 | if (std::size_t pos = decoded.find("password="); pos != std::string::npos) 26 | { 27 | pos += sizeof("password=")-1zu; 28 | peer->ltoken[1] = decoded.substr(pos); 29 | } 30 | } // @note delete decoded 31 | } 32 | catch (...) { packet::action(*event.peer, "logon_fail", ""); } 33 | peer->read(peer->ltoken[0]); 34 | 35 | /* v5.39 */ 36 | packet::create(*event.peer, false, 0, { 37 | "OnSuperMainStartAcceptLogonHrdxs47254722215a", 38 | 2179708244u, // @note items.dat 39 | "ubistatic-a.akamaihd.net", 40 | "0098/0181220253/cache/", 41 | "cc.cz.madkite.freedom org.aqua.gg idv.aqua.bulldog com.cih.gamecih2 com.cih.gamecih com.cih.game_cih cn.maocai.gamekiller com.gmd.speedtime org.dax.attack com.x0.strai.frep com.x0.strai.free org.cheatengine.cegui org.sbtools.gamehack com.skgames.traffikrider org.sbtoods.gamehaca com.skype.ralder org.cheatengine.cegui.xx.multi1458919170111 com.prohiro.macro me.autotouch.autotouch com.cygery.repetitouch.free com.cygery.repetitouch.pro com.proziro.zacro com.slash.gamebuster", 42 | "proto=225|choosemusic=audio/mp3/tsirhc.mp3|active_holiday=9|wing_week_day=0|ubi_week_day=0|server_tick=51938460|game_theme=winterfest-theme|clash_active=0|drop_lavacheck_faster=1|isPayingUser=1|usingStoreNavigation=1|enableInventoryTab=1|bigBackpack=1|seed_diary_hash=2264386986", 43 | 0u // @note player_tribute.dat 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /include/action/input.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "commands/__command.hpp" 3 | #include "tools/string.hpp" 4 | #include "input.hpp" 5 | 6 | #if defined(_MSC_VER) 7 | using namespace std::chrono; 8 | #else 9 | using namespace std::chrono::_V2; 10 | #endif 11 | 12 | void action::input(ENetEvent& event, const std::string& header) 13 | { 14 | auto &peer = _peer[event.peer]; 15 | 16 | std::vector pipes = readch(header, '|'); 17 | if (pipes.size() < 5) return; 18 | if (pipes[3] != "text") return; 19 | 20 | std::string text = pipes[4]; 21 | 22 | if (text.front() == '\r' || std::ranges::all_of(text, ::isspace)) return; 23 | text.erase(text.begin(), std::find_if_not(text.begin(), text.end(), ::isspace)); 24 | text.erase(std::find_if_not(text.rbegin(), text.rend(), ::isspace).base(), text.end()); 25 | 26 | steady_clock::time_point now = steady_clock::now(); 27 | peer->messages.push_back(now); 28 | if (peer->messages.size() > 5) peer->messages.pop_front(); 29 | if (peer->messages.size() == 5 && duration_cast(now - peer->messages.front()).count() < 6) 30 | packet::create(*event.peer, false, 0, { 31 | "OnConsoleMessage", 32 | "`6>>`4Spam detected! ``Please wait a bit before typing anything else. " 33 | "Please note, any form of bot/macro/auto-paste will get all your accounts banned, so don't do it!" 34 | }); 35 | else if (text.starts_with('/')) 36 | { 37 | packet::action(*event.peer, "log", std::format("msg| `6{}``", text)); 38 | std::string command = text.substr(1, text.find(' ') - 1); 39 | 40 | if (auto it = cmd_pool.find(command); it != cmd_pool.end()) 41 | it->second(std::ref(event), std::move(text.substr(1))); 42 | else 43 | packet::action(*event.peer, "log", "msg|`4Unknown command.`` Enter `$/?`` for a list of valid commands."); 44 | } 45 | else 46 | { 47 | if (peer->state & S_DUCT_TAPE) text = "mfmm"; // @todo scalewith length of message. e.g. "hello" -> "mfmm"; "hello world" -> "mfmm mmfmfm" 48 | const char* talkBubble = std::format("CP:0_PL:0_OID:_player_chat={}", text).c_str(); 49 | const char* message = std::format("CP:0_PL:0_OID:_CT:[W]_ `6<`{}{}``>`` `$`${}````", peer->prefix, peer->ltoken[0], text).c_str(); 50 | peers(event, PEER_SAME_WORLD, [&peer, talkBubble, message](ENetPeer& p) 51 | { 52 | packet::create(p, false, 0, { "OnTalkBubble", peer->netid, talkBubble }); 53 | packet::create(p, false, 0, { "OnConsoleMessage", message }); 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /include/action/__action.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "logging_in.hpp" 4 | #include "refresh_item_data.hpp" 5 | #include "enter_game.hpp" 6 | 7 | #include "dialog_return.hpp" 8 | #include "friends.hpp" 9 | 10 | #include "join_request.hpp" 11 | #include "quit_to_exit.hpp" 12 | #include "respawn.hpp" 13 | #include "setSkin.hpp" 14 | #include "input.hpp" 15 | #include "drop.hpp" 16 | #include "info.hpp" 17 | #include "trash.hpp" 18 | #include "wrench.hpp" 19 | #include "itemfavourite.hpp" 20 | #include "inventoryfavuitrigger.hpp" 21 | #include "store.hpp" 22 | #include "buy.hpp" 23 | 24 | #include "quit.hpp" 25 | 26 | #include "__action.hpp" 27 | 28 | std::unordered_map> action_pool 29 | { 30 | {"protocol", std::bind(&action::logging_in, std::placeholders::_1, std::placeholders::_2)}, 31 | {"action|refresh_item_data", std::bind(&action::refresh_item_data, std::placeholders::_1, std::placeholders::_2)}, 32 | {"action|enter_game", std::bind(&action::enter_game, std::placeholders::_1, std::placeholders::_2)}, 33 | 34 | {"action|dialog_return", std::bind(&action::dialog_return, std::placeholders::_1, std::placeholders::_2)}, 35 | {"action|friends", std::bind(&action::friends, std::placeholders::_1, std::placeholders::_2)}, 36 | 37 | {"action|join_request", std::bind(&action::join_request, std::placeholders::_1, std::placeholders::_2, "")}, 38 | {"action|quit_to_exit", std::bind(&action::quit_to_exit, std::placeholders::_1, std::placeholders::_2, false)}, 39 | {"action|respawn", std::bind(&action::respawn, std::placeholders::_1, std::placeholders::_2)}, 40 | {"action|respawn_spike", std::bind(&action::respawn, std::placeholders::_1, std::placeholders::_2)}, 41 | {"action|setSkin", std::bind(&action::setSkin, std::placeholders::_1, std::placeholders::_2)}, 42 | {"action|input", std::bind(&action::input, std::placeholders::_1, std::placeholders::_2)}, 43 | {"action|drop", std::bind(&action::drop, std::placeholders::_1, std::placeholders::_2)}, 44 | {"action|info", std::bind(&action::info, std::placeholders::_1, std::placeholders::_2)}, 45 | {"action|trash", std::bind(&action::trash, std::placeholders::_1, std::placeholders::_2)}, 46 | {"action|wrench", std::bind(&action::wrench, std::placeholders::_1, std::placeholders::_2)}, 47 | {"action|itemfavourite", std::bind(&action::itemfavourite, std::placeholders::_1, std::placeholders::_2)}, 48 | {"action|inventoryfavuitrigger", std::bind(&action::inventoryfavuitrigger, std::placeholders::_1, std::placeholders::_2)}, 49 | {"action|store", std::bind(&action::store, std::placeholders::_1, std::placeholders::_2)}, 50 | {"action|buy", std::bind(&action::buy, std::placeholders::_1, std::placeholders::_2)}, 51 | 52 | {"action|quit", std::bind(&action::quit, std::placeholders::_1, std::placeholders::_2)} 53 | }; -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | @copyright gurotopia (c) 2024-05-25 3 | @version perent SHA: 5df8a03cac7a89e2f2ce5929a3617f536885bb4f 2025-12-20 4 | */ 5 | #include "include/pch.hpp" 6 | #include "include/event_type/__event_type.hpp" 7 | 8 | #include "include/database/shouhin.hpp" 9 | #include "include/tools/string.hpp" 10 | #include "include/https/https.hpp" 11 | #include 12 | #include 13 | 14 | int main() 15 | { 16 | /* !! please press Ctrl + C when restarting or stopping server !! */ 17 | std::signal(SIGINT, safe_disconnect_peers); 18 | #ifdef SIGHUP // @note unix 19 | std::signal(SIGHUP, safe_disconnect_peers); // @note PuTTY, SSH problems 20 | #endif 21 | 22 | /* libary version checker */ 23 | printf("ZTzTopia/enet %d.%d.%d\n", ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH); 24 | printf("sqlite/sqlite3 %s\n", sqlite3_libversion()); 25 | printf("openssl/openssl %s\n", OpenSSL_version(OPENSSL_VERSION_STRING)); 26 | 27 | std::filesystem::create_directory("db"); 28 | init_shouhin_tachi(); 29 | 30 | enet_initialize(); 31 | { 32 | ::server_data server_data = init_server_data(); 33 | ENetAddress address{ 34 | .type = ENET_ADDRESS_TYPE_IPV4, 35 | .port = server_data.port 36 | }; 37 | 38 | server = enet_host_create (ENET_ADDRESS_TYPE_IPV4, &address, 50zu/* max peer count */, 2zu, 0, 0); 39 | std::thread(&https::listener, server_data).detach(); 40 | } // @note delete server_data, address 41 | server->usingNewPacketForServer = true; 42 | server->checksum = enet_crc32; 43 | enet_host_compress_with_range_coder(server); 44 | 45 | try // @note for people who don't use a debugger.. 46 | { 47 | const uintmax_t size = std::filesystem::file_size("items.dat"); 48 | 49 | im_data.resize(im_data.size() + size); // @note state + items.dat 50 | im_data[0zu] = PACKET_CREATE; // @note 04 00 00 00 51 | im_data[4zu] = std::byte{ 0x10 }; // @note 16 00 00 00 52 | /* {...} */ 53 | im_data[16zu] = PACKET_STATE; // @note 08 00 00 00 54 | *reinterpret_cast(&im_data[sizeof(::state)]) = size; // @note at the end of ::state, items.dat size and data 55 | 56 | std::ifstream("items.dat", std::ios::binary) 57 | .read(reinterpret_cast(&im_data[60zu]), size); 58 | 59 | printf("storing items.dat in binary; %zu KB of stack memory\n", im_data.size() / 1024); 60 | 61 | cache_items(); 62 | } // @note delete size 63 | catch (std::filesystem::filesystem_error error) { puts(error.what()); } 64 | catch (...) { puts("unknown error occured during decoding items.dat"); } // @note if this appears, it's probably cache_items()... 65 | 66 | ENetEvent event{}; 67 | while (true) 68 | while (enet_host_service(server, &event, 100/*ms*/) > 0) 69 | if (const auto i = event_pool.find(event.type); i != event_pool.end()) 70 | i->second(event); 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /include/action/dialog_return/popup.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | #include "tools/string.hpp" // @note to_char() 4 | 5 | #include "popup.hpp" 6 | 7 | void popup(ENetEvent& event, const std::vector &&pipes) 8 | { 9 | auto &peer = _peer[event.peer]; 10 | if (pipes.size() <= 11) return; // @note "Continue" botton on wrench has no data. so we return early. 11 | 12 | if (pipes[11zu] == "my_worlds") 13 | { 14 | auto section = [](const auto& range) 15 | { 16 | std::string result; 17 | for (const auto &name : range) 18 | if (!name.empty()) 19 | result.append(std::format("add_button|{0}|{0}|noflags|0|0|\n", name)); 20 | return result; 21 | }; 22 | packet::create(*event.peer, false, 0, { 23 | "OnDialogRequest", 24 | std::format( 25 | "set_default_color|`o\n" 26 | "start_custom_tabs|\n" 27 | "add_custom_button|myWorldsUiTab_0|image:interface/large/btn_tabs2.rttex;image_size:228,92;frame:1,0;width:0.15;|\n" 28 | "add_custom_button|myWorldsUiTab_1|image:interface/large/btn_tabs2.rttex;image_size:228,92;frame:0,1;width:0.15;|\n" 29 | "add_custom_button|myWorldsUiTab_2|image:interface/large/btn_tabs2.rttex;image_size:228,92;frame:0,2;width:0.15;|\n" 30 | "end_custom_tabs|\n" 31 | "add_label|big|Locked Worlds|left|0|\n" 32 | "add_spacer|small|\n" 33 | "add_textbox|Place a World Lock in a world to lock it. Break your World Lock to unlock a world.|left|\n" 34 | "add_spacer|small|\n" 35 | "{}\n" 36 | "add_spacer|small|\n" 37 | "end_dialog|worlds_list||Back|\n" 38 | "add_quick_exit|\n", 39 | section(peer->my_worlds) 40 | ).c_str() 41 | }); 42 | } 43 | else if (pipes[11zu] == "billboard_edit") 44 | { 45 | packet::create(*event.peer, false, 0, { 46 | "OnDialogRequest", 47 | std::format("set_default_color|`o\n" 48 | "add_label_with_icon|big|`wTrade Billboard``|left|8282|\n" 49 | "add_spacer|small|\n" 50 | "{}" 51 | "add_item_picker|billboard_item|`wSelect Billboard Item``|Choose an item to put on your billboard!|\n" 52 | "add_spacer|small|\n" 53 | "add_checkbox|billboard_toggle|`$Show Billboard``|{}\n" 54 | "add_checkbox|billboard_buying_toggle|`$Is Buying``|{}\n" 55 | "add_text_input|setprice|Price of item:|{}|5|\n" 56 | "add_checkbox|chk_peritem|World Locks per Item|{}\n" 57 | "add_checkbox|chk_perlock|Items per World Lock|{}\n" 58 | "add_spacer|small|\n" 59 | "end_dialog|billboard_edit|Close|Update|\n", 60 | (peer->billboard.id == 0) ? 61 | "" : 62 | std::format("add_label_with_icon|small|`w{}``|left|{}|\n", items[peer->billboard.id].raw_name, peer->billboard.id), 63 | to_char(peer->billboard.show), 64 | to_char(peer->billboard.isBuying), 65 | peer->billboard.price, 66 | to_char(peer->billboard.perItem), 67 | to_char(!peer->billboard.perItem) 68 | ).c_str() 69 | }); 70 | } 71 | } -------------------------------------------------------------------------------- /include/commands/weather.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "weather.hpp" 4 | 5 | int get_weather_id(u_int item_id) 6 | { 7 | switch (item_id) 8 | { 9 | case 830: return 1; // @note beach (blast) 10 | case 934: return 2; // @note night 11 | case 946: return 3; // @note arid 12 | 13 | case 984: return 5; // @note rainy city 14 | case 1060: return 6; // @note harvest moon (blast) 15 | case 1136: return 7; // @note mars (blast) 16 | case 1210: return 8; // @note spooky 17 | 18 | case 1490: return 10; // @note nothingness 19 | case 1364: return 11; // @note snowy 20 | 21 | case 1532: return 14; // @note undersea (blast) 22 | case 1750: return 15; // @note warp speed 23 | 24 | case 2046: return 17; // @note comet 25 | case 2284: return 18; // @note party 26 | case 2744: return 19; // @note pineapples 27 | case 3252: return 20; // @note snowy night 28 | case 3446: return 21; // @note spring 29 | case 3534: return 22; // @note howling sky 30 | 31 | case 3694: return 23; // @note heatwave (24-28) 32 | 33 | case 3832: return 29; // @note stuff 34 | case 4242: return 30; // @note pagoda 35 | case 4486: return 31; // @note apocalypse 36 | case 4774: return 32; // @note jungle (blast) 37 | case 4892: return 33; // @note balloon warz 38 | case 5000: return 34; // @note background 39 | case 5112: return 35; // @note autumn 40 | case 5654: return 36; // @note valentine's 41 | case 5716: return 37; // @note St. paddy's 42 | 43 | case 6854: return 42; // @note digital rain 44 | case 7380: return 43; // @note monochrome (blast) 45 | case 7644: return 44; // @note frozen cliffs 46 | case 8556: return 45; // @note surg world (blast) 47 | case 8738: return 46; // @note bountiful (blast) 48 | case 8836: return 47; // @note stargazing 49 | case 8896: return 48; // @note meteor shower 50 | 51 | case 10286: return 51; // @note celebrity hills 52 | case 11880: return 59; // @note plaza 53 | case 12054: return 60; // @note nebula 54 | case 12056: return 61; // @note protostar landing 55 | case 12408: return 62; // @note dark mountains 56 | 57 | case 12844: return 64; // @note Mt. growmore 58 | case 13004: return 65; // @note crack in reality 59 | case 13070: return 66; // @note 年兽 (nián) mountains 60 | 61 | case 13640: return 69; // @note realm of spirits 62 | case 13690: return 70; // @note black hole 63 | case 14032: return 71; // @note raining gems 64 | case 14094: return 72; // @note holiday heaven 65 | 66 | case 14598: return 76; // @note atlantis 67 | case 14802: return 77; // @note pinuski's petal purrfect haven 68 | case 14896: return 78; // @note candyland blast 69 | case 15150: return 79; // @note dragon's keep 70 | case 15240: return 80; // @note emerald city 71 | } 72 | return 0; // @note sunny 73 | } 74 | 75 | void weather(ENetEvent& event, const std::string_view text) 76 | { 77 | if (text.length() <= sizeof("weather ") - 1) 78 | { 79 | packet::create(*event.peer, false, 0, { "OnConsoleMessage", "`^Usage: /weather {id}" }); 80 | return; 81 | } 82 | std::string id{ text.substr(sizeof("weather ") - 1) }; 83 | 84 | try 85 | { 86 | packet::create(*event.peer, false, 0, { 87 | "OnSetCurrentWeather", 88 | stoi(id) 89 | }); 90 | } 91 | catch (const std::invalid_argument &ex) 92 | { 93 | packet::create(*event.peer, false, 0, { 94 | "OnConsoleMessage", 95 | "`4Invalid input. ``id must be a `wnumber``." 96 | }); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | **グロートピア** *(Gurotopia)* : Lightweight & Maintained GTPS written in C/C++ 4 | 5 | [![](https://github.com/GT-api/GT.api/actions/workflows/make.yml/badge.svg)](https://github.com/GT-api/GT.api/actions/workflows/make.yml) 6 | [![Dockerfile](https://github.com/gurotopia/Gurotopia/actions/workflows/docker.yml/badge.svg)](https://github.com/gurotopia/Gurotopia/actions/workflows/docker.yml) 7 | [![](https://app.codacy.com/project/badge/Grade/fa8603d6ec2b4485b8e24817ef23ca21)](https://app.codacy.com/gh/gurotopia/Gurotopia/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) 8 | [![](https://dcbadge.limes.pink/api/server/zzWHgzaF7J?style=flat)](https://discord.gg/zzWHgzaF7J) 9 | 10 |
11 | 12 | *** 13 | 14 | # Windows_logo_and_wordmark_-_2021 svg 15 | 16 | #### ![](https://raw.githubusercontent.com/microsoft/vscode-icons/main/icons/dark/archive.svg) 1. Install Dependencies 17 | - download [**MSYS2**](https://www.msys2.org/) and [**Visual Studio Code**](https://code.visualstudio.com/): install [C/C++ extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) for VSC (**Required**) 18 | 19 | - Locate your MSYS2 folder (e.g., `C:\msys64`), open `ucrt64.exe`, and run the following command: 20 | ```bash 21 | pacman -S --needed mingw-w64-ucrt-x86_64-{gcc,openssl,sqlite} make 22 | ``` 23 | 24 | #### ![](https://raw.githubusercontent.com/microsoft/vscode-icons/main/icons/dark/build.svg) 2. Compile 25 | - Open the project folder in Visual Studio Code. 26 | - Press **`Ctrl + Shift + B`** to start the build process. 27 | 28 | #### ![](https://raw.githubusercontent.com/microsoft/vscode-icons/main/icons/dark/debug-alt-small.svg) 3. Run/Debug 29 | - After compiling, press **`F5`** to run the server with the debugger attached. 30 | 31 | # Linux 32 | 33 | #### ![](https://raw.githubusercontent.com/microsoft/vscode-icons/main/icons/dark/archive.svg) 1. Install Dependencies 34 | 35 | - enter command associated with your distribution into the terminal to install nessesary tools. 36 |
Arch 37 |

38 | 39 | ```bash 40 | sudo pacman -S base-devel openssl sqlite 41 | ``` 42 |

43 |
44 |
Debian Ubuntu 45 |

46 | 47 | ```bash 48 | sudo apt-get update && sudo apt-get install build-essential libssl-dev openssl sqlite3 49 | ``` 50 | 51 |

52 |
53 | 54 | #### ![](https://raw.githubusercontent.com/microsoft/vscode-icons/main/icons/dark/build.svg) 2. Compile 55 | - Navigate to the project's root directory in your terminal and run the `make` command: 56 | ```bash 57 | make -j$(nproc) 58 | ``` 59 | 60 | #### ![](https://raw.githubusercontent.com/microsoft/vscode-icons/main/icons/dark/debug-alt-small.svg) 3. Run 61 | - Execute the compiled binary located in the `main` directory: 62 | ```bash 63 | ./main.out 64 | ``` 65 | 66 | --- 67 | 68 | ### ![](https://raw.githubusercontent.com/microsoft/vscode-icons/main/icons/dark/settings.svg) Local Server Configuration 69 | 70 | > [!NOTE] 71 | > To connect to your local server, you must modify your system's **hosts** file. 72 | > - **Windows**: `C:\Windows\System32\drivers\etc\hosts` 73 | > - **Linux/macOS**: `/etc/hosts` 74 | > 75 | > Add the following lines to the end of the file: 76 | > ``` 77 | > 127.0.0.1 www.growtopia1.com 78 | > 127.0.0.1 www.growtopia2.com 79 | > ``` 80 | -------------------------------------------------------------------------------- /include/tools/create_dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "create_dialog.hpp" 3 | 4 | create_dialog& create_dialog::set_default_color(std::string code) 5 | { 6 | _d.append(std::format("set_default_color|{}\n", code)); 7 | return *this; 8 | } 9 | create_dialog& create_dialog::add_label(std::string size, std::string label) 10 | { 11 | _d.append(std::format("add_label|{}|{}|left\n", size, label)); 12 | return *this; 13 | } 14 | create_dialog& create_dialog::add_label_with_icon(std::string size, std::string label, int icon) 15 | { 16 | _d.append(std::format("add_label_with_icon|{}|{}|left|{}|\n", size, label, icon)); 17 | return *this; 18 | } 19 | create_dialog& create_dialog::add_label_with_ele_icon(std::string size, std::string label, int icon, u_char element) 20 | { 21 | _d.append(std::format("add_label_with_ele_icon|{}|{}|left|{}|{}|\n", size, label, icon, element)); 22 | return *this; 23 | } 24 | create_dialog& create_dialog::add_textbox(std::string label) 25 | { 26 | _d.append(std::format("add_textbox|{}|left|\n", label)); 27 | return *this; 28 | } 29 | create_dialog& create_dialog::add_text_input(std::string id, std::string label, short set_value, short length) 30 | { 31 | _d.append(std::format("add_text_input|{}|{}|{}|{}|\n", id, label, set_value, length)); 32 | return *this; 33 | } 34 | create_dialog& create_dialog::add_text_input(std::string id, std::string label, std::string set_value, short length) 35 | { 36 | _d.append(std::format("add_text_input|{}|{}|{}|{}|\n", id, label, set_value, length)); 37 | return *this; 38 | } 39 | create_dialog& create_dialog::embed_data(std::string id, std::string data) 40 | { 41 | _d.append(std::format("embed_data|{}|{}\n", id, data)); 42 | return *this; 43 | } 44 | create_dialog& create_dialog::embed_data(std::string id, int data) 45 | { 46 | _d.append(std::format("embed_data|{}|{}\n", id, data)); 47 | return *this; 48 | } 49 | create_dialog& create_dialog::add_spacer(std::string size) 50 | { 51 | _d.append(std::format("add_spacer|{}|\n", size)); 52 | return *this; 53 | } 54 | create_dialog& create_dialog::set_custom_spacing(short x, short y) 55 | { 56 | _d.append(std::format("set_custom_spacing|x:{};y:{}|\n", x, y)); 57 | return *this; 58 | } 59 | create_dialog& create_dialog::add_button(std::string btn_id, std::string btn_name) 60 | { 61 | _d.append(std::format("add_button|{}|{}|noflags|0|0|\n", btn_id, btn_name)); 62 | return *this; 63 | } 64 | create_dialog& create_dialog::add_custom_button(std::string btn_id, std::string image) 65 | { 66 | _d.append(std::format("add_custom_button|{}|{}|\n", btn_id, image)); 67 | return *this; 68 | } 69 | create_dialog& create_dialog::add_custom_label(std::string btn_id, std::string pos) 70 | { 71 | _d.append(std::format("add_custom_label|{}|{}|\n", btn_id, pos)); 72 | return *this; 73 | } 74 | create_dialog& create_dialog::add_custom_break() 75 | { 76 | _d.append("add_custom_break|\n"); 77 | return *this; 78 | } 79 | create_dialog& create_dialog::add_custom_margin(short x, short y) 80 | { 81 | _d.append(std::format("add_custom_margin|x:{};y:{}|\n", x, y)); 82 | return *this; 83 | } 84 | create_dialog& create_dialog::add_achieve(std::string total) 85 | { 86 | _d.append(std::format("add_achieve|||left|{}|\n", total)); // @todo 87 | return *this; 88 | } 89 | create_dialog& create_dialog::add_quick_exit() 90 | { 91 | _d.append("add_quick_exit|\n"); 92 | return *this; 93 | } 94 | create_dialog& create_dialog::add_popup_name(std::string popup_name) 95 | { 96 | _d.append(std::format("add_popup_name|{}|\n", popup_name)); 97 | return *this; 98 | } 99 | create_dialog& create_dialog::add_player_info(std::string label, std::string progress_bar_name, int progress, int total_progress) 100 | { 101 | _d.append(std::format("add_player_info|{}|{}|{}|{}|\n", label, progress_bar_name, progress, total_progress)); 102 | return *this; 103 | } 104 | 105 | std::string create_dialog::end_dialog(std::string btn_id, std::string btn_close, std::string btn_return) 106 | { 107 | _d.append(std::format("end_dialog|{}|{}|{}|\n", btn_id, btn_close, btn_return)); 108 | return _d; 109 | } -------------------------------------------------------------------------------- /include/https/https.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "https.hpp" 3 | 4 | #include 5 | 6 | #ifdef _WIN32 7 | #include 8 | #include 9 | #else 10 | #include 11 | #include 12 | #include 13 | #include // @note TCP_DEFER_ACCEPT 14 | #include 15 | 16 | #define SOCKET int 17 | #endif 18 | 19 | void https::listener(::server_data server_data) 20 | { 21 | OpenSSL_add_all_algorithms(); 22 | SSL_load_error_strings(); 23 | constexpr int enable = 1; 24 | 25 | SSL_CTX *ctx = SSL_CTX_new(TLS_server_method()); 26 | if (ctx == nullptr) 27 | ERR_print_errors_fp(stderr); 28 | 29 | if (SSL_CTX_use_certificate_file(ctx, "resources/ctx/server.crt", SSL_FILETYPE_PEM) <= 0 || 30 | SSL_CTX_use_PrivateKey_file(ctx, "resources/ctx/server.key", SSL_FILETYPE_PEM) <= 0) 31 | ERR_print_errors_fp(stderr); 32 | 33 | SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); 34 | SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305"); 35 | 36 | SOCKET socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 37 | 38 | setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char*)&enable, sizeof(enable)); 39 | #ifdef TCP_FASTOPEN 40 | setsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, (char*)&enable, sizeof(enable)); 41 | #endif 42 | #ifdef TCP_DEFER_ACCEPT // @note unix 43 | setsockopt(socket, IPPROTO_TCP, TCP_DEFER_ACCEPT, &enable, sizeof(enable)); 44 | #endif 45 | struct sockaddr_in addr; 46 | addr.sin_family = AF_INET; 47 | addr.sin_addr.s_addr = INADDR_ANY; 48 | addr.sin_port = htons(443); 49 | socklen_t addrlen = sizeof(addr); 50 | if (bind(socket, (struct sockaddr*)&addr, addrlen) < 0) 51 | puts("could not bind port 443."); 52 | 53 | printf("listening on %s:%hu\n", server_data.server.c_str(), server_data.port); 54 | 55 | const std::string Content = 56 | std::format( 57 | "server|{}\n" 58 | "port|{}\n" 59 | "type|{}\n" 60 | "type2|{}\n" 61 | "#maint|{}\n" 62 | "loginurl|{}\n" 63 | "meta|{}\n" 64 | "RTENDMARKERBS1001", 65 | server_data.server, server_data.port, server_data.type, server_data.type2, server_data.maint, server_data.loginurl, server_data.meta 66 | ); 67 | const std::string response = 68 | std::format( 69 | "HTTP/1.1 200 OK\r\n" 70 | "Content-Type: text/plain\r\n" 71 | "Content-Length: {}\r\n" 72 | "Connection: close\r\n\r\n" 73 | "{}", 74 | Content.size(), Content); 75 | 76 | listen(socket, SOMAXCONN); // @todo 77 | while (true) 78 | { 79 | SOCKET fd = accept(socket, (struct sockaddr*)&addr, &addrlen); 80 | if (fd < 0) continue; 81 | 82 | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&enable, sizeof(enable)); 83 | 84 | SSL *ssl = SSL_new(ctx); 85 | SSL_set_fd(ssl, fd); 86 | 87 | if (SSL_accept(ssl) > 0) 88 | { 89 | 90 | char buf[213]; // @note size of growtopia's POST request. 91 | const int length{ sizeof(buf) }; 92 | 93 | if (SSL_read(ssl, buf, length) == length) 94 | { 95 | puts(buf); 96 | 97 | if (std::string_view(buf, sizeof(buf )).contains("POST /growtopia/server_data.php HTTP/1.1")) 98 | { 99 | SSL_write(ssl, response.c_str(), response.size()); 100 | SSL_shutdown(ssl); 101 | } 102 | } 103 | else ERR_print_errors_fp(stderr); // @note we don't accept growtopia GET. this error is normal if appears. 104 | } 105 | else ERR_print_errors_fp(stderr); 106 | SSL_free(ssl); 107 | #ifdef _WIN32 108 | closesocket(fd); 109 | #else 110 | close(fd); 111 | #endif 112 | } 113 | } 114 | 115 | #ifndef _WIN32 116 | #undef SOCKET 117 | #endif -------------------------------------------------------------------------------- /include/packet/packet.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "packet.hpp" 3 | 4 | void packet::create(ENetPeer& p, bool netid, signed delay, const std::vector& params) 5 | { 6 | std::vector data(61, std::byte{ 00 }); 7 | data[0zu] = PACKET_CREATE; 8 | data[4zu] = std::byte{ 01 }; 9 | *reinterpret_cast(&data[8zu]) = (!netid) ? -1 : _peer[&p]->netid; 10 | data[16zu] = PACKET_STATE; 11 | *reinterpret_cast(&data[24zu]) = delay; 12 | // @note 04 00 00 00 01 00 00 00 {netid} {...8} 08 00 00 00 {...8} {delay} 13 | 14 | std::size_t size = data.size(); 15 | std::byte index{}; 16 | for (const std::any ¶m : params) 17 | { 18 | if (param.type() == typeid(const char*)) 19 | { 20 | std::string_view param_view{ std::any_cast(param) }; 21 | data.resize(size + 2zu + sizeof(int) + param_view.length()); 22 | data[size] = index; // @note element counter e.g. "OnConsoleMessage" -> 00, "hello" -> 01 23 | data[size + 1zu] = std::byte{ 02 }; 24 | *reinterpret_cast(&data[size + 2zu]) = param_view.length(); 25 | 26 | const std::byte *_1bit = reinterpret_cast(param_view.data()); 27 | for (std::size_t i = 0zu; i < param_view.length(); ++i) 28 | data[size + 6zu + i] = _1bit[i]; // @note e.g. 'a' -> 0x61. 'z' = 0x7A, hex tabel: https://en.cppreference.com/w/cpp/language/ascii 29 | 30 | size += 2zu + sizeof(int) + param_view.length(); 31 | } 32 | else if (param.type() == typeid(int) || param.type() == typeid(u_int)) 33 | { 34 | bool is_signed = (param.type() == typeid(int)); 35 | auto value = is_signed ? std::any_cast(param) : std::any_cast(param); 36 | data.resize(size + 2zu + sizeof(value)); 37 | data[size] = index; // @note element counter e.g. "OnSetBux" -> 00, 43562/-43562 -> 01 38 | data[size + 1zu] = (is_signed) ? std::byte{ 0x09 } : std::byte{ 05 }; 39 | 40 | const std::byte *_1bit = reinterpret_cast(&value); 41 | for (std::size_t i = 0zu; i < sizeof(value); ++i) 42 | data[size + 2zu + i] = _1bit[i]; 43 | 44 | size += 2zu + sizeof(value); 45 | } 46 | else if (param.type() == typeid(std::vector)) 47 | { 48 | const std::vector& vec = std::any_cast&>(param); 49 | data.resize(size + 2zu + (sizeof(float) * vec.size())); 50 | data[size] = index; 51 | data[size + 1zu] = 52 | (vec.size() == 1zu) ? std::byte{ 01 } : 53 | (vec.size() == 2zu) ? std::byte{ 03 } : 54 | (vec.size() == 3zu) ? std::byte{ 04 } : 55 | std::byte{ 00 }; 56 | 57 | const std::byte *_1bit = reinterpret_cast(vec.data()); 58 | for (std::size_t i = 0zu; i < sizeof(float) * vec.size(); ++i) 59 | data[size + 2zu + i] = _1bit[i]; 60 | 61 | size += 2zu + (sizeof(float) * vec.size()); 62 | } 63 | else return; // @note this will never pass unless you include a param that Growtopia does not recognize 64 | 65 | index = static_cast(std::to_integer(index) + 1); 66 | data[60zu] = index; 67 | } 68 | 69 | enet_peer_send(&p, 0, enet_packet_create(data.data(), size, ENET_PACKET_FLAG_RELIABLE)); 70 | } 71 | 72 | void packet::action(ENetPeer& p, const std::string& action, const std::string& str) 73 | { 74 | std::string_view action_view = std::format("action|{}\n", action); 75 | std::vector data(4 + action_view.length() + str.length(), std::byte{ 00 }); 76 | data[0zu] = std::byte{ 03 }; 77 | { 78 | const std::byte *_1bit = reinterpret_cast(action_view.data()); 79 | for (std::size_t i = 0zu; i < action_view.length(); ++i) 80 | data[4zu + i] = _1bit[i]; 81 | } 82 | if (!str.empty()) 83 | { 84 | const std::byte *_1bit = reinterpret_cast(str.data()); 85 | for (std::size_t i = 0zu; i < str.length(); ++i) 86 | data[4zu + action_view.length() + i] = _1bit[i]; 87 | } 88 | 89 | enet_peer_send(&p, 0, enet_packet_create(data.data(), data.size(), ENET_PACKET_FLAG_RELIABLE)); 90 | } -------------------------------------------------------------------------------- /include/database/world.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef WORLD_HPP 3 | #define WORLD_HPP 4 | 5 | enum wstate3 : u_char 6 | { 7 | S_RIGHT = 0x00, 8 | S_LOCKED = 0x10, 9 | S_LEFT = 0x20, 10 | S_TOGGLE = 0x40, // @note including mailbox which just toggles the visuals 11 | S_PUBLIC = 0x80 12 | }; 13 | 14 | /* locks that only occupy a number of tiles, and not the whole world. */ 15 | #define is_tile_lock(id) (id == 202/*small*/ || id == 204/*big*/ || id == 206/*huge*/ || id == 4994/*builder*/) 16 | 17 | enum wstate4 : u_char 18 | { 19 | S_WATER = 0x04, 20 | S_GLUE = 0x08, 21 | S_FIRE = 0x10, 22 | /* paint buckets */ 23 | S_RED = 0x20, 24 | S_GREEN = 0x40, 25 | S_YELLOW = S_RED | S_GREEN, 26 | S_BLUE = 0x80, 27 | S_AQUA = S_GREEN | S_BLUE, 28 | S_PURPLE = S_RED | S_BLUE, 29 | S_CHARCOAL = S_RED | S_GREEN | S_BLUE, 30 | S_VANISH = S_RED | S_YELLOW | S_GREEN | S_AQUA | S_BLUE | S_PURPLE | S_CHARCOAL 31 | }; 32 | 33 | struct block 34 | { 35 | block( 36 | short _fg = 0, short _bg = 0, 37 | std::chrono::steady_clock::time_point _tick = std::chrono::steady_clock::time_point(), 38 | std::string _label = "", u_char _state3 = 0, u_char _state4 = 0 39 | ) : fg(_fg), bg(_bg), tick(_tick), label(_label), state3(_state3), state4(_state4) {} 40 | short fg{0}, bg{0}; 41 | 42 | std::chrono::steady_clock::time_point tick{}; // @note record a point in time for the tile e.g. tree growth, providers, ect. 43 | std::string label{}; // @note sign/door label 44 | 45 | u_char state3{}; // @note direction; visuals | uses wstate3:: 46 | u_char state4{}; // @note water; glue; fire; paint | uses wstate4:: 47 | 48 | std::array hits{0, 0}; // @note fg, bg 49 | }; 50 | #define cord(x,y) (y * 100 + x) 51 | 52 | struct door 53 | { 54 | door(std::string _dest, std::string _id, std::string _password, ::pos _pos) : 55 | dest(_dest), id(_id), password(_password), pos(_pos) {} 56 | 57 | std::string dest{}; 58 | std::string id{}; 59 | std::string password{}; 60 | ::pos pos; 61 | }; 62 | 63 | struct ifloat 64 | { 65 | ifloat(short _id, short _count, std::array _pos) : id(_id), count(_count), pos(_pos) {} 66 | short id{0}; 67 | short count{0}; 68 | std::array pos; 69 | }; 70 | 71 | class world 72 | { 73 | public: 74 | world(const std::string& name = ""); 75 | std::string name{}; 76 | 77 | int owner{ 00 }; // @note owner of world using peer's user id. 78 | std::array admin{}; // @note admins (by user id). excluding owner. (6 is a experimental amount, if increase update me if any issue occur -leeendl) 79 | bool _public{}; // @note checks if world is public to break/place 80 | 81 | u_char visitors{0}; // @note the current number of peers in a world, excluding invisable peers 82 | 83 | std::vector<::block> blocks; // @note all blocks, size of 1D meaning (6000) instead of 2D (100, 60) 84 | std::vector<::door> doors; 85 | int ifloat_uid{0}; // @note floating item UID 86 | std::unordered_map ifloats{}; // @note (i)tem floating 87 | ~world(); 88 | }; 89 | extern std::unordered_map worlds; 90 | 91 | extern void send_data(ENetPeer& peer, const std::vector &&data); 92 | 93 | extern void state_visuals(ENetEvent& event, state &&s); 94 | 95 | extern void tile_apply_damage(ENetEvent& event, state s, block& b); 96 | 97 | extern void modify_item_inventory(ENetEvent& event, ::slot slot); 98 | 99 | extern int item_change_object(ENetEvent& event, ::slot slot, const std::array& pos, signed uid = 0); 100 | 101 | extern void tile_update(ENetEvent &event, state s, block &b, world& w); 102 | 103 | void generate_world(world &world, const std::string& name); 104 | 105 | bool door_mover(world &world, const ::pos &pos); 106 | 107 | namespace blast 108 | { 109 | void thermonuclear(world &world, const std::string& name); 110 | } 111 | 112 | #endif -------------------------------------------------------------------------------- /linux-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # © XeyyzuV2 4 | 5 | echo "Gurotopia installer 2025-9-23 sha-48701e5f8a9082e3f2b6c42cd29fecdc3c488f95" 6 | echo 7 | 8 | # Check if the script is run with root privileges (sudo) 9 | if [ "$(id -u)" -ne 0 ]; then 10 | echo "Error: This script must be run with root privileges." >&2 11 | echo "Please try again using: sudo ./installer.sh" >&2 12 | exit 1 13 | fi 14 | 15 | # Check if the OS is Debian-based 16 | if [ -f /etc/debian_version ]; then 17 | echo "Debian-based system detected. Proceeding with installation using apt-get..." 18 | echo 19 | 20 | # 1. Initial package list update 21 | echo "[1/4] Running initial apt-get update..." 22 | apt-get update -y 23 | if [ $? -ne 0 ]; then 24 | echo "Failed to update package list. Please check your internet connection or try again later." >&2 25 | exit 1 26 | fi 27 | echo "Initial update finished." 28 | echo 29 | 30 | # 2. Install software-properties-common to manage PPAs 31 | echo "[2/4] Installing software-properties-common..." 32 | apt-get install -y software-properties-common 33 | if [ $? -ne 0 ]; then 34 | echo "Failed to install software-properties-common." >&2 35 | exit 1 36 | fi 37 | echo "software-properties-common installed." 38 | echo 39 | 40 | # 3. Add PPA for modern GCC and update again 41 | echo "[3/4] Adding PPA for modern GCC (ppa:ubuntu-toolchain-r/test)..." 42 | add-apt-repository ppa:ubuntu-toolchain-r/test -y 43 | if [ $? -ne 0 ]; then 44 | echo "Failed to add PPA. Please check the output above for details." >&2 45 | exit 1 46 | fi 47 | echo "PPA added successfully. Running apt-get update again..." 48 | apt-get update -y 49 | echo "Update finished." 50 | echo 51 | 52 | # 4. Install all dependencies including g++-13 53 | echo "[4/4] Installing dependencies: build-essential libssl-dev openssl sqlite3 libsqlite3-dev g++-13..." 54 | apt-get install -y build-essential libssl-dev openssl sqlite3 libsqlite3-dev g++-13 55 | if [ $? -ne 0 ]; then 56 | echo "Failed to install dependencies. Please check the output above for error details." >&2 57 | exit 1 58 | fi 59 | echo "Dependency installation finished." 60 | echo 61 | 62 | # 5. Set g++-13 as default gcc/g++ using update-alternatives 63 | echo "[5/5] Setting g++-13 as default compiler..." 64 | if [ -f /usr/bin/gcc-13 ] && [ -f /usr/bin/g++-13 ]; then 65 | update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 66 | update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 100 67 | update-alternatives --set gcc /usr/bin/gcc-13 68 | update-alternatives --set g++ /usr/bin/g++-13 69 | echo "g++-13 set as default compiler." 70 | else 71 | echo "Warning: gcc-13 or g++-13 not found. Please check if g++-13 was installed correctly." 72 | fi 73 | echo 74 | 75 | echo "======================================" 76 | echo "Installation Successful!" 77 | echo "You can now compile the server by running the command: make -j$(nproc)" 78 | echo "======================================" 79 | 80 | # Check if the OS is Arch-based 81 | elif [ -f /etc/arch-release ]; then 82 | echo "Arch-based system detected. Proceeding with installation using pacman..." 83 | echo 84 | 85 | # 1. Update package database 86 | echo "[1/4] Updating package database..." 87 | pacman -Sy --noconfirm 88 | if [ $? -ne 0 ]; then 89 | echo "Failed to update package database. Please check your internet connection or try again later." >&2 90 | exit 1 91 | fi 92 | echo "Package database updated." 93 | echo 94 | 95 | # 2. Install base development tools 96 | echo "[2/4] Installing base-devel..." 97 | pacman -S --noconfirm --needed base-devel 98 | if [ $? -ne 0 ]; then 99 | echo "Failed to install base-devel." >&2 100 | exit 1 101 | fi 102 | echo "base-devel installed." 103 | echo 104 | 105 | # 3. Install additional dependencies 106 | echo "[3/4] Installing additional dependencies: openssl sqlite..." 107 | pacman -S --noconfirm --needed openssl sqlite 108 | if [ $? -ne 0 ]; then 109 | echo "Failed to install additional dependencies." >&2 110 | exit 1 111 | fi 112 | echo "Additional dependencies installed." 113 | echo 114 | 115 | echo "======================================" 116 | echo "Installation Successful!" 117 | echo "You can now compile the server by running the command: make -j$(nproc)" 118 | echo "======================================" 119 | else 120 | echo "Error: This script supports Debian-based (Ubuntu, Debian, Mint) and Arch-based (Arch, Manjaro) systems." >&2 121 | echo "Please install the following dependencies manually for your distribution:" >&2 122 | echo " - A modern C++ compiler (g++ version 13+)" >&2 123 | echo " - build-essential (or base-devel on Arch)" >&2 124 | echo " - libssl-dev" >&2 125 | echo " - openssl" >&2 126 | echo " - sqlite3 (or sqlite on Arch)" >&2 127 | exit 1 128 | fi 129 | 130 | exit 0 131 | -------------------------------------------------------------------------------- /include/database/peer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PEER_HPP 3 | #define PEER_HPP 4 | 5 | /* id, count */ 6 | struct slot { 7 | slot(short _id, short _count) : id(_id), count(_count) {} 8 | short id{0}; 9 | short count{0}; // @note total amount of that item 10 | }; 11 | 12 | /* x, y */ // @todo add float positions 13 | struct pos { 14 | pos(int _x, int _y) : x(_x), y(_y) {} 15 | int x{0}; 16 | int y{0}; 17 | 18 | auto operator<=>(const pos&) const = default; 19 | }; 20 | 21 | struct Billboard { 22 | short id{0}; // @note the item they're selling 23 | bool show{}; 24 | bool isBuying{}; 25 | int price{1}; 26 | bool perItem{}; // @note true if world locks per item, false if items per world lock 27 | }; 28 | 29 | struct Friend { 30 | std::string name{}; 31 | bool ignore{}; 32 | bool block{}; 33 | bool mute{}; 34 | }; 35 | 36 | enum role : u_char { 37 | PLAYER, 38 | MODERATOR, 39 | DEVELOPER 40 | }; 41 | 42 | enum pstate : int 43 | { 44 | S_GHOST = 0x01, 45 | S_DOUBLE_JUMP = 0x02, 46 | S_DUCT_TAPE = 0x2000 47 | }; 48 | 49 | #include 50 | #include 51 | #if defined(_MSC_VER) 52 | #undef max 53 | #undef min 54 | #endif 55 | 56 | class peer { 57 | public: 58 | peer& read(const std::string& name); 59 | 60 | signed netid{ 0 }; // @note peer's netid is world identity. this will be useful for many packet sending 61 | int user_id{}; // @note unqiue user id. 62 | std::array ltoken{}; // @note {growid, password} 63 | std::string prefix{ "w" }; // @note display name color, default: "w" (White) 64 | u_char role{}; 65 | std::array clothing{}; // @note peer's clothing {id, clothing::} 66 | u_char punch_effect{}; // @note last equipped clothing that has a effect. supporting 0-255 effects. 67 | 68 | unsigned skin_color{ 2527912447 }; 69 | 70 | int state{}; // @note using pstate:: 71 | 72 | Billboard billboard{}; 73 | 74 | std::array pos{}; // @note position {x, y} 75 | std::array rest_pos{}; // @note respawn position {x, y} 76 | bool facing_left{}; // @note peer is directed towards the left direction 77 | 78 | short slot_size{16}; // @note amount of slots this peer has | were talking total slots not itemed slots, to get itemed slots do slot.size() 79 | std::vector slots{{18, 1}, {32, 1}}; // @note an array of each slot. storing {id, count} 80 | /* 81 | * @brief set slot::count to nagative value if you want to remove an amount. 82 | * @return the remaining amount if exeeds 200. e.g. emplace(slot{0, 201}) returns 1. 83 | */ 84 | short emplace(slot s); 85 | std::vector fav{}; 86 | 87 | signed gems{0}; 88 | std::array level{ 1, 0 }; // {level, xp} XP formula credits: https://www.growtopiagame.com/forums/member/553046-kasete 89 | /* 90 | * @brief add XP safely, this function also handles level up. 91 | */ 92 | void add_xp(u_short value); 93 | 94 | std::array recent_worlds{}; // @note recent worlds, a list of 6 worlds, once it reaches 7 it'll be replaced by the oldest 95 | std::array my_worlds{}; // @note first 200 relevant worlds locked by peer. 96 | 97 | std::deque messages; // @note last 5 que messages sent time, this is used to check for spamming 98 | 99 | std::array friends; 100 | 101 | ~peer(); 102 | }; 103 | #include 104 | 105 | extern std::unordered_map> _peer; 106 | 107 | extern ENetHost* server; 108 | 109 | #include 110 | 111 | enum peer_condition 112 | { 113 | PEER_ALL, // @note all peer(s) 114 | PEER_SAME_WORLD // @note only peer(s) in the same world as ENetEvent::peer 115 | }; 116 | 117 | extern std::vector peers(ENetEvent event, peer_condition condition = PEER_ALL, std::function fun = [](ENetPeer& peer){}); 118 | 119 | void safe_disconnect_peers(int signal); 120 | 121 | class state { 122 | public: 123 | int packet_create{ 04 }; 124 | 125 | int type{}; 126 | int netid{}; 127 | int uid{}; // @todo understand this better @note so far I think this holds uid value 128 | int peer_state{}; 129 | float count{}; // @todo understand this better 130 | int id{}; // @note peer's active hand, so 18 (fist) = punching, 32 (wrench) interacting, ect... 131 | std::array pos{}; // @note position 1D {x, y} 132 | std::array speed{}; // @note player movement (velocity(x), gravity(y)), higher gravity = smaller jumps 133 | ::pos punch{0,0}; // @note punching/placing position 2D {x, y} 134 | 135 | u_char idk{}; // @note last bit in a packet 136 | }; 137 | 138 | extern state get_state(const std::vector &&packet); 139 | 140 | /* put it back into it's original form */ 141 | extern std::vector compress_state(const state &s); 142 | 143 | extern void inventory_visuals(ENetEvent &event); 144 | 145 | #endif -------------------------------------------------------------------------------- /include/database/items.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "items.hpp" 3 | 4 | std::unordered_map items; 5 | std::vector im_data(61, std::byte{ 00 }); 6 | 7 | template 8 | void shift_pos(std::vector& data, u_int& pos, T& value) 9 | { 10 | for (std::size_t i = 0zu; i < sizeof(T); ++i) 11 | reinterpret_cast(&value)[i] = data[pos + i]; 12 | pos += sizeof(T); 13 | } 14 | 15 | /* have not tested modifying string values... */ 16 | template 17 | void data_modify(std::vector& data, u_int& pos, const T& value) 18 | { 19 | for (std::size_t i = 0zu; i < sizeof(T); ++i) 20 | data[pos + i] = reinterpret_cast(&value)[i]; 21 | } 22 | 23 | void cache_items() 24 | { 25 | u_int pos{60}; 26 | u_char version{}; 27 | shift_pos(im_data, pos, version); pos += 1; // @note downsize 'version' to 1 bit 28 | u_short count{}; 29 | shift_pos(im_data, pos, count); pos += 2; // @note downside count to 2 bit 30 | static constexpr std::string_view token{"PBG892FXX982ABC*"}; 31 | for (u_short i = 0; i < count; ++i) 32 | { 33 | item im{}; 34 | 35 | shift_pos(im_data, pos, im.id); pos += 2; // @note downside im.id to 2 bit (short) 36 | shift_pos(im_data, pos, im.property); 37 | 38 | shift_pos(im_data, pos, im.cat); 39 | if (im.id == 6336) im.cat = 0x80; // @todo or |= 40 | 41 | shift_pos(im_data, pos, im.type); 42 | pos += sizeof(std::byte); 43 | 44 | short len = *(reinterpret_cast(&im_data[pos])); 45 | pos += sizeof(short); 46 | im.raw_name.resize(len); 47 | for (short i = 0; i < len; ++i) 48 | im.raw_name[i] = std::to_integer(im_data[pos]) ^ token[(i + im.id) % token.length()], 49 | ++pos; 50 | 51 | pos += *(reinterpret_cast(&im_data[pos])); 52 | pos += sizeof(short); 53 | 54 | pos += sizeof(std::array); 55 | 56 | shift_pos(im_data, pos, im.collision); 57 | { 58 | std::byte raw_hits{}; 59 | shift_pos(im_data, pos, raw_hits); 60 | im.hits = std::to_integer(raw_hits); 61 | if (im.hits != 0) im.hits /= 6; // @note unknown reason behind why break hit is muliplied by 6 then having to divide by 6 62 | } // @note delete raw_hits 63 | shift_pos(im_data, pos, im.hit_reset); 64 | 65 | if (im.type == type::CLOTHING) 66 | { 67 | std::byte cloth_type{}; 68 | shift_pos(im_data, pos, cloth_type); 69 | im.cloth_type = std::to_integer(cloth_type); 70 | } 71 | else pos += 1; // @note assign nothing 72 | if (im.type == type::AURA) im.cloth_type = clothing::ances; 73 | shift_pos(im_data, pos, im.rarity); 74 | 75 | pos += sizeof(std::byte); 76 | 77 | len = *reinterpret_cast(&im_data[pos]); 78 | pos += sizeof(short); 79 | 80 | im.audio_directory.assign(reinterpret_cast(&im_data[pos]), len); 81 | pos += len; 82 | 83 | if (im.audio_directory.ends_with(".mp3")) 84 | data_modify(im_data, pos, 0); // @todo make it only for IOS 85 | shift_pos(im_data, pos, im.audioHash); 86 | 87 | pos += sizeof(std::array); 88 | 89 | pos += *(reinterpret_cast(&im_data[pos])); 90 | pos += sizeof(short); 91 | 92 | pos += *(reinterpret_cast(&im_data[pos])); 93 | pos += sizeof(short); 94 | 95 | pos += *(reinterpret_cast(&im_data[pos])); 96 | pos += sizeof(short); 97 | 98 | pos += *(reinterpret_cast(&im_data[pos])); 99 | pos += sizeof(short); 100 | 101 | pos += sizeof(std::array); 102 | 103 | shift_pos(im_data, pos, im.tick); 104 | 105 | pos += sizeof(short); 106 | pos += sizeof(short); 107 | 108 | pos += *(reinterpret_cast(&im_data[pos])); 109 | pos += sizeof(short); 110 | 111 | pos += *(reinterpret_cast(&im_data[pos])); 112 | pos += sizeof(short); 113 | 114 | pos += *(reinterpret_cast(&im_data[pos])); 115 | pos += sizeof(short); 116 | 117 | pos += sizeof(std::array); 118 | 119 | if (version >= 11) 120 | { 121 | pos += *(reinterpret_cast(&im_data[pos])); 122 | pos += sizeof(short); 123 | } 124 | if (version >= 12) 125 | { 126 | pos += sizeof(int); 127 | pos += sizeof(std::array); 128 | } 129 | if (version >= 13) pos += sizeof(int); 130 | if (version >= 14) pos += sizeof(int); 131 | if (version >= 15) 132 | { 133 | pos += sizeof(std::array); 134 | pos += *(reinterpret_cast(&im_data[pos])); 135 | pos += sizeof(short); 136 | } 137 | if (version >= 16) 138 | { 139 | pos += *(reinterpret_cast(&im_data[pos])); 140 | pos += sizeof(short); 141 | } 142 | if (version >= 17) pos += sizeof(int); 143 | if (version >= 18) pos += sizeof(int); 144 | if (version >= 19) pos += sizeof(std::array); 145 | if (version >= 21) pos += sizeof(short); 146 | if (version >= 22) 147 | { 148 | short len = *reinterpret_cast(&im_data[pos]); 149 | pos += sizeof(short); 150 | im.info.assign(reinterpret_cast(&im_data[pos]), len); 151 | pos += len; 152 | } 153 | if (version >= 23) 154 | { 155 | shift_pos(im_data, pos, im.splice[0]); 156 | shift_pos(im_data, pos, im.splice[1]); 157 | } 158 | if (version == 24) pos += sizeof(std::byte); 159 | 160 | 161 | items.emplace(i, im); 162 | } 163 | printf("parsed %zu items; %zu KB of stack memory\n", items.size(), (items.size() * sizeof(item)) / 1024); 164 | } 165 | -------------------------------------------------------------------------------- /include/enet/protocol.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file protocol.h 3 | @brief ENet protocol 4 | */ 5 | #ifndef __ENET_PROTOCOL_H__ 6 | #define __ENET_PROTOCOL_H__ 7 | 8 | #include "enet/types.h" 9 | 10 | enum 11 | { 12 | ENET_PROTOCOL_MINIMUM_MTU = 576, 13 | ENET_PROTOCOL_MAXIMUM_MTU = 4096, 14 | ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, 15 | ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, 16 | ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, 17 | ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, 18 | ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, 19 | ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, 20 | ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 21 | }; 22 | 23 | typedef enum _ENetProtocolCommand 24 | { 25 | ENET_PROTOCOL_COMMAND_NONE = 0, 26 | ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, 27 | ENET_PROTOCOL_COMMAND_CONNECT = 2, 28 | ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, 29 | ENET_PROTOCOL_COMMAND_DISCONNECT = 4, 30 | ENET_PROTOCOL_COMMAND_PING = 5, 31 | ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, 32 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, 33 | ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, 34 | ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, 35 | ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, 36 | ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, 37 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, 38 | ENET_PROTOCOL_COMMAND_COUNT = 13, 39 | 40 | ENET_PROTOCOL_COMMAND_MASK = 0x0F 41 | } ENetProtocolCommand; 42 | 43 | typedef enum _ENetProtocolFlag 44 | { 45 | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), 46 | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), 47 | 48 | ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), 49 | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), 50 | ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, 51 | 52 | ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), 53 | ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 54 | } ENetProtocolFlag; 55 | 56 | #ifdef _MSC_VER 57 | #pragma pack(push, 1) 58 | #define ENET_PACKED 59 | #elif defined(__GNUC__) || defined(__clang__) 60 | #define ENET_PACKED __attribute__ ((packed)) 61 | #else 62 | #define ENET_PACKED 63 | #endif 64 | 65 | typedef struct _ENetProtocolHeader 66 | { 67 | enet_uint16 peerID; 68 | enet_uint16 sentTime; 69 | } ENET_PACKED ENetProtocolHeader; 70 | 71 | typedef struct _ENetNewProtocolHeader 72 | { 73 | enet_uint16 integrity[3]; 74 | enet_uint16 peerID; 75 | enet_uint16 sentTime; 76 | } ENET_PACKED ENetNewProtocolHeader; 77 | 78 | typedef struct _ENetProtocolCommandHeader 79 | { 80 | enet_uint8 command; 81 | enet_uint8 channelID; 82 | enet_uint16 reliableSequenceNumber; 83 | } ENET_PACKED ENetProtocolCommandHeader; 84 | 85 | typedef struct _ENetProtocolAcknowledge 86 | { 87 | ENetProtocolCommandHeader header; 88 | enet_uint16 receivedReliableSequenceNumber; 89 | enet_uint16 receivedSentTime; 90 | } ENET_PACKED ENetProtocolAcknowledge; 91 | 92 | typedef struct _ENetProtocolConnect 93 | { 94 | ENetProtocolCommandHeader header; 95 | enet_uint16 outgoingPeerID; 96 | enet_uint8 incomingSessionID; 97 | enet_uint8 outgoingSessionID; 98 | enet_uint32 mtu; 99 | enet_uint32 windowSize; 100 | enet_uint32 channelCount; 101 | enet_uint32 incomingBandwidth; 102 | enet_uint32 outgoingBandwidth; 103 | enet_uint32 packetThrottleInterval; 104 | enet_uint32 packetThrottleAcceleration; 105 | enet_uint32 packetThrottleDeceleration; 106 | enet_uint32 connectID; 107 | enet_uint32 data; 108 | } ENET_PACKED ENetProtocolConnect; 109 | 110 | typedef struct _ENetProtocolVerifyConnect 111 | { 112 | ENetProtocolCommandHeader header; 113 | enet_uint16 outgoingPeerID; 114 | enet_uint8 incomingSessionID; 115 | enet_uint8 outgoingSessionID; 116 | enet_uint32 mtu; 117 | enet_uint32 windowSize; 118 | enet_uint32 channelCount; 119 | enet_uint32 incomingBandwidth; 120 | enet_uint32 outgoingBandwidth; 121 | enet_uint32 packetThrottleInterval; 122 | enet_uint32 packetThrottleAcceleration; 123 | enet_uint32 packetThrottleDeceleration; 124 | enet_uint32 connectID; 125 | } ENET_PACKED ENetProtocolVerifyConnect; 126 | 127 | typedef struct _ENetProtocolBandwidthLimit 128 | { 129 | ENetProtocolCommandHeader header; 130 | enet_uint32 incomingBandwidth; 131 | enet_uint32 outgoingBandwidth; 132 | } ENET_PACKED ENetProtocolBandwidthLimit; 133 | 134 | typedef struct _ENetProtocolThrottleConfigure 135 | { 136 | ENetProtocolCommandHeader header; 137 | enet_uint32 packetThrottleInterval; 138 | enet_uint32 packetThrottleAcceleration; 139 | enet_uint32 packetThrottleDeceleration; 140 | } ENET_PACKED ENetProtocolThrottleConfigure; 141 | 142 | typedef struct _ENetProtocolDisconnect 143 | { 144 | ENetProtocolCommandHeader header; 145 | enet_uint32 data; 146 | } ENET_PACKED ENetProtocolDisconnect; 147 | 148 | typedef struct _ENetProtocolPing 149 | { 150 | ENetProtocolCommandHeader header; 151 | } ENET_PACKED ENetProtocolPing; 152 | 153 | typedef struct _ENetProtocolSendReliable 154 | { 155 | ENetProtocolCommandHeader header; 156 | enet_uint16 dataLength; 157 | } ENET_PACKED ENetProtocolSendReliable; 158 | 159 | typedef struct _ENetProtocolSendUnreliable 160 | { 161 | ENetProtocolCommandHeader header; 162 | enet_uint16 unreliableSequenceNumber; 163 | enet_uint16 dataLength; 164 | } ENET_PACKED ENetProtocolSendUnreliable; 165 | 166 | typedef struct _ENetProtocolSendUnsequenced 167 | { 168 | ENetProtocolCommandHeader header; 169 | enet_uint16 unsequencedGroup; 170 | enet_uint16 dataLength; 171 | } ENET_PACKED ENetProtocolSendUnsequenced; 172 | 173 | typedef struct _ENetProtocolSendFragment 174 | { 175 | ENetProtocolCommandHeader header; 176 | enet_uint16 startSequenceNumber; 177 | enet_uint16 dataLength; 178 | enet_uint32 fragmentCount; 179 | enet_uint32 fragmentNumber; 180 | enet_uint32 totalLength; 181 | enet_uint32 fragmentOffset; 182 | } ENET_PACKED ENetProtocolSendFragment; 183 | 184 | typedef union _ENetProtocol 185 | { 186 | ENetProtocolCommandHeader header; 187 | ENetProtocolAcknowledge acknowledge; 188 | ENetProtocolConnect connect; 189 | ENetProtocolVerifyConnect verifyConnect; 190 | ENetProtocolDisconnect disconnect; 191 | ENetProtocolPing ping; 192 | ENetProtocolSendReliable sendReliable; 193 | ENetProtocolSendUnreliable sendUnreliable; 194 | ENetProtocolSendUnsequenced sendUnsequenced; 195 | ENetProtocolSendFragment sendFragment; 196 | ENetProtocolBandwidthLimit bandwidthLimit; 197 | ENetProtocolThrottleConfigure throttleConfigure; 198 | } ENET_PACKED ENetProtocol; 199 | 200 | #ifdef _MSC_VER 201 | #pragma pack(pop) 202 | #endif 203 | 204 | #endif /* __ENET_PROTOCOL_H__ */ 205 | 206 | -------------------------------------------------------------------------------- /include/database/items.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ITEMS_HPP 3 | #define ITEMS_HPP 4 | 5 | enum clothing : u_short { 6 | hair, shirt, legs, 7 | feet, face, hand, 8 | back, head, charm, 9 | ances, none 10 | }; 11 | 12 | enum type : u_char { 13 | FIST = 00, 14 | WRENCH = 01, 15 | DOOR = 02, 16 | LOCK = 03, 17 | GEM = 04, 18 | TREASURE = 05, 19 | DEADLY = 06, 20 | TRAMPOLINE = 07, 21 | CONSUMEABLE = 0x08, 22 | ENTRANCE = 0x09, 23 | SIGN = 0x0a, 24 | SFX_BLOCK = 0x0b, 25 | TOGGLEABLE_ANIMATED_BLOCK = 0x0c, 26 | MAIN_DOOR = 0x0d, 27 | PLATFORM = 0x0e, 28 | STRONG = 0x0f, // @note too strong to break 29 | FIRE_PAIN = 0x10, 30 | FOREGROUND = 0x11, 31 | BACKGROUND = 0x12, 32 | SEED = 0x13, 33 | CLOTHING = 0x14, 34 | ANIMATED = 0x15, 35 | SFX_BACKGROUND = 0x16, 36 | ART_WALL = 0x17, 37 | BOUNCHY = 0x18, 38 | STING_PAIN = 0x19, 39 | PORTAL = 0x1a, 40 | CHECKPOINT = 0x1b, 41 | MUSIC_SHEET = 0x1c, 42 | SLIPPERY = 0x1d, 43 | TOGGLEABLE_BLOCK = 0x1f, 44 | CHEST = 0x20, 45 | MAILBOX = 0x21, 46 | BULLETIN = 0x22, 47 | PINATA = 0x23, 48 | RANDOM = 0x24, 49 | COMPONET = 0x25, 50 | PROVIDER = 0x26, 51 | CHEMICAL_COMBINER = 0x27, 52 | ACHIEVEMENT = 0x28, 53 | WEATHER_MACHINE = 0x29, 54 | SCOREBOARD = 0x2a, 55 | SUNGATE = 0x2b, 56 | TOGGLEABLE_DEADLY = 0x2d, 57 | HEART_MONITOR = 0x2e, 58 | DONATION_BOX = 0x2f, 59 | MANNEQUIN = 0x31, 60 | CCTV = 0x32, 61 | MAGIC_EGG = 0x33, 62 | GAME_BLOCK = 0x34, 63 | GAME_GENERATOR = 0x35, 64 | XENONITE = 0x36, 65 | BOOTH = 0x37, 66 | CRYSTAL = 0x38, 67 | CRIME_IN_PROGRESS = 0x39, 68 | GRINDER = 0x3a, 69 | SPOTLIGHT = 0x3b, 70 | PUSHING_BLOCK = 0x3c, 71 | DISPLAY_BLOCK = 0x3d, 72 | VENDING_MACHINE = 0x3e, 73 | FISH_TANK_PORT = 0x3f, 74 | FISH = 0x40, 75 | SOLAR_COLLECTOR = 0x41, 76 | FORGE = 0x42, 77 | GIVING_TREE = 0x43, 78 | GIVING_TREE_STUMP = 0x44, 79 | STEAM_BLOCK = 0x45, 80 | STEAM_VENT = 0x46, 81 | STEAM_ORGAN = 0x47, 82 | SILKWORM = 0x48, 83 | SEWING_MACHINE = 0x49, 84 | COUNTRY_FLAG = 0x4a, 85 | LOBSTER_TRAP = 0x4b, 86 | PAINTING_EASEL = 0x4c, 87 | BATTLE_PET_CAGE = 0x4d, 88 | PET_TRAINER = 0x4e, 89 | STEAM_ENGINE = 0x4f, 90 | LOCK_BOT = 0x50, 91 | SFX_WEATHER_MACHINE = 0x51, // @note Heatwave, Balloon Warz, Background, Valetine's, St.Paddy, Digital Rain Weather Machines 92 | SPIRIT_STORAGE = 0x52, 93 | DISPLAY_SHELF = 0x53, 94 | VIP_ENTRANCE = 0x54, 95 | CHALLENGE_TIMER = 0x55, 96 | CHALLENGE_FLAG = 0x56, 97 | FISH_MOUNT = 0x57, 98 | PORTRAIT = 0x58, 99 | SPRITE_WEATHER_MACHINE = 0x59, // @note Stuff, Guild, Epoch Weather Machines, 100 | FOSSIL = 0x5a, 101 | FOSSIL_PREP_STATION = 0x5b, 102 | DNA_PROCESSOR = 0x5c, 103 | TRICKSTER = 0x5d, 104 | VALHOWLA_TREASURE = 0x5e, 105 | CHEMSYNTH_PROCESSOR = 0x5f, 106 | CHEMSYNTH_TANK = 0x60, 107 | STORAGE_BOX = 0x61, 108 | COOKING_OVEN = 0x62, 109 | AUDIO_BLOCK = 0x63, 110 | GEIGER_CHARGER = 0x64, 111 | THE_ADVENTURE_BEGINS = 0x65, 112 | TOMB_ROBBER = 0x66, 113 | BALLOON_O_MATIC = 0x67, 114 | TEAM_ENTRANCE_PUNCH = 0x68, 115 | TEAM_ENTRANCE_GROW = 0x69, 116 | TEAM_ENTRANCE_BUILD = 0x6a, 117 | AURA = 0x6b, // @note including ances 118 | LEMON_JELLY_BLOCK = 0x6c, 119 | TRAINING_PORT = 0x6d, 120 | FISHING_BLOCK = 0x6e, 121 | MAGPLANT = 0x6f, 122 | MAGPLANT_REMOTE = 0x70, 123 | CYBLOCK_BOT = 0x71, 124 | CYBLOCK_COMMAND = 0x72, 125 | LUCKY_TOKEN = 0x73, 126 | GROWSCAN = 0x74, 127 | CONTAINMENT_FIELD_POWER_NODE = 0x75, 128 | SPIRIT_BOARD = 0x76, 129 | WORLD_ARCHITECT = 0x77, 130 | STARTOPIA_BLOCK = 0x78, 131 | TOGGLEABLE_MULTI_FRAME_BLOCK = 0x7a, 132 | AUTO_BREAK_BLOCK = 0x7b, 133 | AUTO_BREAK_TREE = 0x7c, 134 | AUTO_BREAK = 0x7d, 135 | STORM_CLOUD = 0x7e, 136 | DISAPPEAR_WHEN_STEPPED_ON = 0x7f, 137 | PUDDLE_BLOCK = 0x80, 138 | ROOT_CUTTING = 0x81, 139 | SAFE_VAULT = 0x82, 140 | ANGELIC_COUNTING_CLOUD = 0x83, 141 | MINING_EXPLOSIVE = 0x84, 142 | INFINITY_WEATHER_MACHINE = 0x86, 143 | GHOST_BLOCK = 0x87, 144 | ACID = 0x88, 145 | WAVING_INFLATABLE_ARM_GUY = 0x8a, 146 | PINEAPPLE_GUZZLER = 0x8c, 147 | KRANKEN_GALACTIC = 0x8d, 148 | FRIEND_ENTRANCE = 0x8e, 149 | }; 150 | 151 | enum cat : u_char { 152 | CAT_RETURN = 02, // @note This item can't be destroyed - smashing it will return it to your backpack if you have room! 153 | CAT_CANNOT_DROP = 0x80 // @note This item cannot be dropped or traded. 154 | }; 155 | 156 | #include 157 | 158 | namespace collision { 159 | const std::byte 160 | no_collision{ 00 }, 161 | full{ 01 }, 162 | platform{ 02 }, 163 | entrance{ 03 }, 164 | toggle{ 04 }, 165 | horizontal{ 05 }, 166 | vip{ 06 }, // @note VIP entrance 167 | vertical{ 07 }, 168 | adventure_item{ 0x08 }, 169 | activate{ 0x09 }, 170 | balloon_warz_team{ 0x0a }, // @note team entrance 171 | guild{ 0x0b }, // @note guild entrance 172 | step_on{ 0x0c }; 173 | } 174 | 175 | class item 176 | { 177 | public: 178 | u_short id{}; /* item identity */ 179 | std::byte property{}; 180 | u_char cat{}; 181 | u_char type{}; 182 | std::string raw_name{}; /* the exact name of the item including uppercases */ 183 | std::byte collision{}; 184 | short hits{}; // @todo make it unsigned. 185 | int hit_reset{}; // @note in seconds 186 | u_short cloth_type{clothing::none}; /* use clothing:: if you are unsure of the order */ 187 | short rarity{}; 188 | std::string audio_directory{}; // @note ../../audio.mp3 189 | int audioHash{}; 190 | int tick{}; // @note tile tick time e.g. trees, providers, ect.. (measured in seconds) 191 | 192 | std::string info{}; // @note version 22 | item's info 193 | 194 | std::array splice{}; // @note version 23 | {seed1, seed2} 195 | }; 196 | extern std::unordered_map items; 197 | 198 | extern std::vector im_data; 199 | 200 | extern void cache_items(); 201 | 202 | #endif -------------------------------------------------------------------------------- /include/action/wrench.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "tools/string.hpp" 3 | #include "tools/create_dialog.hpp" 4 | #include "wrench.hpp" 5 | 6 | #include 7 | 8 | void action::wrench(ENetEvent& event, const std::string& header) 9 | { 10 | std::vector pipes = readch(header, '|'); 11 | if ((pipes[3zu] == "netid" && !pipes[4zu].empty()/*empty netid*/)) 12 | { 13 | const short netid = atoi(pipes[4zu].c_str()); 14 | peers(event, PEER_SAME_WORLD, [event, netid](ENetPeer& p) 15 | { 16 | if (_peer[&p]->netid == netid) 17 | { 18 | auto &peer = _peer[&p]; 19 | u_short lvl = peer->level.front(); 20 | /* wrench yourself */ 21 | if (peer->user_id == _peer[event.peer]->user_id) 22 | { 23 | packet::create(*event.peer, false, 0, { 24 | "OnDialogRequest", 25 | ::create_dialog() 26 | .embed_data("netID", netid) 27 | .add_popup_name("WrenchMenu") 28 | .set_default_color("`o") 29 | .add_player_info(std::format("`{}{}``", peer->prefix, peer->ltoken[0]), std::to_string(lvl), peer->level.back(), 50 * (lvl * lvl + 2)) 30 | .add_spacer("small") 31 | .add_spacer("small") 32 | .add_button("renew_pvp_license", "Get Card Battle License") 33 | .add_spacer("small") 34 | .set_custom_spacing(5, 10) 35 | .add_custom_button("open_personlize_profile", "image:interface/large/gui_wrench_personalize_profile.rttex;image_size:400,260;width:0.19;") 36 | .add_custom_button("set_online_status", "image:interface/large/gui_wrench_online_status_1green.rttex;image_size:400,260;width:0.19;") 37 | .add_custom_button("billboard_edit", "image:interface/large/gui_wrench_edit_billboard.rttex;image_size:400,260;width:0.19;") 38 | .add_custom_button("wardrobe_customization", "image:interface/large/gui_wrench_wardrobe.rttex;image_size:400,260;width:0.19;") 39 | .add_custom_button("notebook_edit", "image:interface/large/gui_wrench_notebook.rttex;image_size:400,260;width:0.19;") 40 | .add_custom_button("goals", "image:interface/large/gui_wrench_goals_quests.rttex;image_size:400,260;width:0.19;") 41 | .add_custom_button("bonus", "image:interface/large/gui_wrench_daily_bonus_active.rttex;image_size:400,260;width:0.19;") 42 | .add_custom_button("my_worlds", "image:interface/large/gui_wrench_my_worlds.rttex;image_size:400,260;width:0.19;") 43 | .add_custom_button("alist", "image:interface/large/gui_wrench_achievements.rttex;image_size:400,260;width:0.19;") 44 | .add_custom_label("(0/173)"/*@todo add achivements*/, "target:alist;top:0.72;left:0.5;size:small") 45 | .add_custom_button("emojis", "image:interface/large/gui_wrench_growmojis.rttex;image_size:400,260;width:0.19;") 46 | .add_custom_button("marvelous_missions", "image:interface/large/gui_wrench_marvelous_missions.rttex;image_size:400,260;width:0.19;") 47 | .add_custom_button("title_edit", "image:interface/large/gui_wrench_title.rttex;image_size:400,260;width:0.19;") 48 | .add_custom_button("trade_scan", "image:interface/large/gui_wrench_trades.rttex;image_size:400,260;width:0.19;") 49 | .embed_data("netID", netid) // @todo research why rgt adds this twice... 50 | .add_custom_button("pets", "image:interface/large/gui_wrench_battle_pets.rttex;image_size:400,260;width:0.19;") 51 | .add_custom_button("wrench_customization", "image:interface/large/gui_wrench_customization.rttex;image_size:400,260;width:0.19;") 52 | .add_custom_button("open_worldlock_storage", "image:interface/large/gui_wrench_auction.rttex;image_size:400,260;width:0.19;") 53 | .add_custom_break() 54 | .add_spacer("small") 55 | .set_custom_spacing(0, 0) // @todo research why rgt adds this too. is 0, 0 unaffecting? or is this resetting the previous 5, 10 spacing 56 | .add_spacer("small") 57 | .add_textbox("Surgeon Level: 0") 58 | .add_spacer("small") 59 | .add_textbox("`wActive effects:``") 60 | /* @todo handle peer's effects */ 61 | .add_spacer("small") 62 | .add_textbox(std::format("`oYou have `w{}`` backpack slots.``", peer->slot_size)) 63 | .add_textbox(std::format("`oCurrent world: `w{}`` (`w{}``, `w{}``) (`w0`` person)````", peer->recent_worlds.back(), std::round(peer->pos[0]), std::round(peer->pos[1]))) 64 | .add_spacer("small") 65 | .add_textbox("`oTotal time played is `w0.0`` hours. This account was created `w0`` days ago.``") 66 | .add_spacer("small") 67 | .add_quick_exit() 68 | .end_dialog("popup", "", "Continue").c_str() 69 | }); 70 | } 71 | /* wrench someone else */ 72 | else 73 | { 74 | packet::create(*event.peer, false, 0, { 75 | "OnDialogRequest", 76 | ::create_dialog() 77 | .embed_data("netID", netid) 78 | .add_popup_name("WrenchMenu") 79 | .set_default_color("`o") 80 | .add_label_with_icon("big", std::format("`{}{} (`2{}``)``", peer->prefix, peer->ltoken[0], lvl), 18) 81 | .embed_data("netID", netid) 82 | .add_spacer("small") 83 | .add_achieve("0"/*@todo add achivements*/) 84 | .add_custom_margin(75, -70.85) 85 | .add_custom_margin(-75, 70.85) 86 | .add_spacer("small") 87 | .add_label("small", "`1Achievements:`` 0/173"/*add total achivements*/) 88 | .add_spacer("small") 89 | .add_label("small", "`1Account Age:`` 0 days") 90 | .add_spacer("small") 91 | .add_button("trade", "`wTrade``") 92 | .add_button("sendpm", "`wSend Message``") 93 | .add_textbox("(No Battle Leash equipped)") 94 | .add_textbox("You need a valid license to battle!") 95 | .add_button("friend_add", "`wAdd as friend``") 96 | .add_button("show_clothes", "`wView worn clothes``") 97 | .add_button("ignore_player", "`wIgnore Player``") 98 | .add_button("report_player", "`wReport Player``") 99 | .add_spacer("small") 100 | .add_quick_exit() 101 | .end_dialog("popup", "", "Continue").c_str() 102 | }); 103 | } 104 | return; // @note early exit else iteration will continue for EVERYONE in the world. 105 | } 106 | }); 107 | } 108 | } -------------------------------------------------------------------------------- /include/action/store.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "store.hpp" 3 | 4 | #include "tools/string.hpp" 5 | 6 | std::string payment_site{ "https://discord.gg/zzWHgzaF7J" }; // @note replace with your payment site (paypal, ect) 7 | 8 | void action::store(ENetEvent& event, const std::string& header) 9 | { 10 | std::vector pipes = readch(header, '|'); 11 | 12 | if (header.empty() || pipes[3] == "gem") // @note location|gem 13 | { 14 | packet::create(*event.peer, false, 0, 15 | { 16 | "OnStoreRequest", 17 | std::format( 18 | "set_description_text|Welcome to the `2Growtopia Store``! Select the item you'd like more info on.`o `wThanks for being a supporter of Growtopia!\n" 19 | 20 | /* tabs */ 21 | "enable_tabs|1\n" 22 | "add_tab_button|main_menu|Home|interface/large/btn_shop.rttex||1|0|0|0||||-1|-1|||0|0|CustomParams:|\n" 23 | "add_tab_button|locks_menu|Locks And Stuff|interface/large/btn_shop.rttex||0|1|0|0||||-1|-1|||0|0|CustomParams:|\n" 24 | "add_tab_button|itempack_menu|Item Packs|interface/large/btn_shop.rttex||0|3|0|0||||-1|-1|||0|0|CustomParams:|\n" 25 | "add_tab_button|bigitems_menu|Awesome Items|interface/large/btn_shop.rttex||0|4|0|0||||-1|-1|||0|0|CustomParams:|\n" 26 | "add_tab_button|weather_menu|Weather Machines|interface/large/btn_shop.rttex|Tired of the same sunny sky? We offer alternatives within...|0|5|0|0||||-1|-1|||0|0|CustomParams:|\n" 27 | "add_tab_button|token_menu|Growtoken Items|interface/large/btn_shop.rttex||0|2|0|0||||-1|-1|||0|0|CustomParams:|\n" 28 | 29 | "add_banner|interface/large/gui_shop_featured_header.rttex|0|1|\n" 30 | "add_button|pet_battle_pack|`oPet Battle Pack``|interface/large/store_buttons/store_buttons42.rttex|`2You Get:`` 1 Pet Battle Supply Crate, 1 Battle Leash and 1 Battle Pet Cage.`5Description:`` When a Growtopian plucks up the courage, they can get their own battle pet. This pack contains all the ingredients to create your very own starter Battle Pet and get you ready for your very first Pet Battle. Splicing new battle abilities will cost 10 World Locks per ability, World Locks not included!`4This pack can be only be purchased once.``|1|6|40000|0|||-1|-1||-1|-1||1||||||0|0|CustomParams:|\n" 31 | "add_button|rt_grope_supply_bundle05|`oScrolls Value Pack``|interface/large/store_buttons/store_buttons42.rttex|{0}|2|1|0||||-1|-1||-1|-1|OPENDIALOG&showscrollspurchaseui|1||||||0|0|CustomParams:|\n" 32 | "add_button|rt_grope_supply_bundle04|`oDungeon Pass``|interface/large/store_buttons/store_buttons42.rttex|{0}|1|5|0||||-1|-1||-1|-1|OPENDIALOG&showdungeonpasspurchaseui|1||||||0|0|CustomParams:|\n" 33 | "add_button|rt_grope_battlepass_bundle01|Royal Grow Pass|interface/large/store_buttons/store_buttons37.rttex|{0}|4|2|0||||-1|-1||-1|-1|`2You Get:`` 1 Royal Grow Pass Token.`5Description:`` Play to earn points and level up your Grow Pass to earn rewards. Consume to earn exclusive `5Royal`` rewards as you level up your Grow Pass as well as unlocking all daily bonuses and exclusive `5Royal Perks`` for the entire month. Upon consuming you will instantly receive `2300 Free`` points towards your pass progress. Note: The token is `#UNTRADEABLE``.|1||||||0|0|CustomParams:|\n" 34 | "add_banner|interface/large/gui_shop_featured_header.rttex|0|2|\n" 35 | "add_button|gems_glory|Road To Glory|interface/large/store_buttons/store_buttons30.rttex|{0}|0|0|0||||-1|-1|/interface/large/gui_shop_buybanner.rttex|1|0|`2You Get:`` Road To Glory and 120k Gems Instantly.`5Description:`` Earn Gem rewards when you level up. Every 10 levels you will get additional Gem rewards up to Level 50! Claim all rewards instantly if you are over level 50!! 1.92M Gems in total!!|1||||||0|0|CustomParams:|\n" 36 | "add_button|gems_bundle06|Gem Abundance|interface/large/store_buttons/store_buttons37.rttex|{0}|2|1|0||||-1|-1||-1|-1|`2You Get:`` 19,680,000 Gems, 3,680 World Locks, 10 Growtokens and 5 Megaphones.`5Description:`` Get an abundance of gems to add to your wealth. Please note World Locks will be credited as 36 Diamond Locks and 80 World Locks. Please make sure you have room in your inventory to receive these items.|1||||||0|0|CustomParams:|\n" 37 | "add_button|gems_bundle05|Gem Bounty|interface/large/store_buttons/store_buttons34.rttex|{0}|0|6|0||||-1|-1||-1|-1|`2You Get:`` 10,080,000 Gems, 2,100 World Locks, 6 Growtokens and 3 Megaphones.`5Description:`` Get a plethora of gems to add to your wealth. Please note World Locks will be credited as 21 Diamond Locks. Please make sure you have room in your inventory to receive these items.|1||||||0|0|CustomParams:|\n" 38 | "add_button|gems_rain|It's Rainin' Gems|interface/large/store_buttons/store_buttons.rttex|{0}|1|5|0||||-1|-1||-1|-1|`2You Get:`` 2,730,000 Gems, 630 World Locks, 2 Growtokens and 1 Megaphone.`5Description:`` All the gems you could ever want and more plus 630 World Locks, 2 Growtokens and a Megaphone to tell the whole world about it. Please note World Locks will be credited as 6 Diamond Locks and 30 World Locks. Please make sure you have room in your inventory to receive these items.|1||||||0|0|CustomParams:|\n" 39 | "add_button|gems_fountain|Gem Fountain|interface/large/store_buttons/store_buttons2.rttex|{0}|0|2|0||||-1|-1||-1|-1|`2You Get:`` 922,500 Gems, 260 World Locks and 1 Growtoken.`5Description:`` Get a pile of Gems to shop to your hearts desire, 260 World Locks and 1 Growtoken. Please note World Locks will be credited as 2 Diamond Locks and 60 World Locks. Please make sure you have room in your inventory to receive these items.|1||||||0|0|CustomParams:|\n" 40 | "add_button|gems_chest|Chest o' Gems|interface/large/store_buttons/store_buttons.rttex|{0}|0|5|0||||-1|-1||-1|-1|`2You Get:`` 280,000 Gems and 84 World Locks.`5Description:`` Get a chest containing gems and 84 World Locks. Please make sure you have room in your inventory to receive these items.|1||||||0|0|CustomParams:|\n" 41 | "add_button|grow_shop|`oGrowtopia Shop``|interface/large/store_buttons/store_buttons36.rttex|https://growtopiagame.com/shop|1|1|0|0|Open Shop||-1|-1|interface/large/gui_shop_buybanner.rttex|0|1|If you can purchase Gem Packs through your telecom provider, then open the Growtopia Shop website here.Please note, this service is only available in the following countries: `9Brazil``, `9Cambodia``, `9Estonia``, `9Indonesia``, `9Latvia``, `9Lithuania``, `9Malaysia``, `9Philippines``, `9Qatar``, `9Romania``, `9Saudi Arabia``, `9Singapore``, `9Thailand``, `9Turkey``, and `9United Arab Emirates``|1||||||0|0|CustomParams:|\n" 42 | "add_banner|interface/large/gui_shop_featured_header.rttex|0|3|\n" 43 | "add_image_button|image_button_battlepass_banner|interface/large/gui_shop_grow_pass.rttex|bannerlayout|OPENDIALOG|battlepasspopup||\n" 44 | "add_button|365d|`o1-Year Subscription Token``|interface/large/store_buttons/store_buttons28.rttex|{0}|0|2|0||||-1|-1||-1|-1|`2You Get:`` 1x 1-Year Subscription Token , and 33 Growtokens. `5Description:`` One full year of special treatment AND 33 Growtokens upfront! You'll get 70 season tokens (as long as there's a seasonal clash running), 9600 gems, and 1 World Lock every day and a chance of doubling any XP earned, growtime reduction on all seeds planted and Exclusive Skins!|1||||||0|0|CustomParams:|\n" 45 | "add_button|rt_grope_battlepass_bundle01|Royal Grow Pass|interface/large/store_buttons/store_buttons37.rttex|{0}|4|2|0||||-1|-1||-1|-1|`2You Get:`` 1 Royal Grow Pass Token.`5Description:`` Play to earn points and level up your Grow Pass to earn rewards. Consume to earn exclusive `5Royal`` rewards as you level up your Grow Pass as well as unlocking all daily bonuses and exclusive `5Royal Perks`` for the entire month. Upon consuming you will instantly receive `2300 Free`` points towards your pass progress. Note: The token is `#UNTRADEABLE``.|1||||||0|0|CustomParams:|\n" 46 | "add_button|redeem_code|Redeem Code|interface/large/store_buttons/store_buttons40.rttex|OPENDIALOG&showredeemcodewindow|1|5|0|0|||-1|-1||-1|-1||1||||||0|0|CustomParams:|\n" 47 | ,payment_site 48 | ).c_str() 49 | }); 50 | } 51 | } -------------------------------------------------------------------------------- /include/action/buy.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "store.hpp" 3 | #include "on/SetBux.hpp" 4 | #include "tools/string.hpp" 5 | #include "database/shouhin.hpp" 6 | #include "tools/ransuu.hpp" 7 | #include "buy.hpp" 8 | 9 | 10 | void action::buy(ENetEvent& event, const std::string& header) 11 | { 12 | std::vector pipes = readch(header, '|'); 13 | 14 | auto &peer = _peer[event.peer]; 15 | 16 | short No = (peer->slot_size - 16) / 10 + 1; // @note number of upgrades | credits: https://growtopia.fandom.com/wiki/Backpack_Upgrade 17 | short backpack_cost = (100 * No * No - 200 * No + 200); 18 | 19 | auto growtoken = std::ranges::find_if(peer->slots, [](::slot &slot) { return slot.id == 1486; }); 20 | 21 | short tab{}; 22 | if (pipes[3] == "main") action::store(event, ""); // tab = 0 23 | else if (pipes[3] == "locks") tab = 1; 24 | else if (pipes[3] == "itempack") tab = 2; 25 | else if (pipes[3] == "bigitems") tab = 3; 26 | else if (pipes[3] == "weather") tab = 4; 27 | else if (pipes[3] == "token") tab = 5; 28 | if (tab != 0) 29 | { 30 | std::string StoreRequest{}; 31 | StoreRequest.append( 32 | (tab == 1) ? "set_description_text|`2Locks And Stuff!`` Select the item you'd like more info on, or BACK to go back.\n" : 33 | (tab == 2) ? "set_description_text|`2Item Packs!`` Select the item you'd like more info on, or BACK to go back.\n" : 34 | (tab == 3) ? "set_description_text|`2Awesome Items!`` Select the item you'd like more info on, or BACK to go back.\n" : 35 | (tab == 4) ? "set_description_text|`2Weather Machines!`` Select the item you'd like more info on, or BACK to go back.\n" : 36 | (tab == 5) ? 37 | std::format( 38 | "set_description_text|`2Spend your Growtokens!`` (You have `5{}``) You earn Growtokens from Crazy Jim and Sales-Man. Select the item you'd like more info on, or BACK to go back.\n", 39 | (growtoken != peer->slots.end()) ? growtoken->count : 0) : "" 40 | ); 41 | StoreRequest.append("enable_tabs|1\nadd_tab_button|main_menu|Home|interface/large/btn_shop.rttex||0|0|0|0||||-1|-1|||0|0|CustomParams:|\n"); 42 | StoreRequest.append( 43 | std::format( 44 | "add_tab_button|locks_menu|Locks And Stuff|interface/large/btn_shop.rttex||{}|1|0|0||||-1|-1|||0|0|CustomParams:|\n" 45 | "add_tab_button|itempack_menu|Item Packs|interface/large/btn_shop.rttex||{}|3|0|0||||-1|-1|||0|0|CustomParams:|\n" 46 | "add_tab_button|bigitems_menu|Awesome Items|interface/large/btn_shop.rttex||{}|4|0|0||||-1|-1|||0|0|CustomParams:|\n" 47 | "add_tab_button|weather_menu|Weather Machines|interface/large/btn_shop.rttex|Tired of the same sunny sky? We offer alternatives within...|{}|5|0|0||||-1|-1|||0|0|CustomParams:|\n" 48 | "add_tab_button|token_menu|Growtoken Items|interface/large/btn_shop.rttex||{}|2|0|0||||-1|-1|||0|0|CustomParams:|\n", 49 | (tab == 1) ? "1" : "0", (tab == 2) ? "1" : "0", (tab == 3) ? "1" : "0", (tab == 4) ? "1" : "0", (tab == 5) ? "1" : "0" 50 | )); 51 | for (auto &&[_tab, shouhin] : shouhin_tachi) 52 | { 53 | if (_tab == tab) 54 | { 55 | if (shouhin.btn == "upgrade_backpack") 56 | { 57 | if (No > 38) continue; // @note hide upgrade_backpack in store if maxed out 58 | shouhin.cost = backpack_cost; 59 | } 60 | StoreRequest.append(std::format( 61 | "add_button|{}|{}|{}|{}|{}|{}|{}|0|||-1|-1||-1|-1||1||||||0|0|CustomParams:|\n", 62 | shouhin.btn, shouhin.name, shouhin.rttx, shouhin.description, shouhin.tex1, shouhin.tex2, shouhin.cost 63 | )); 64 | } 65 | } 66 | packet::create(*event.peer, false, 0, { "OnStoreRequest", StoreRequest.c_str() }); 67 | return; 68 | } 69 | else for (auto &&[_tab, shouhin] : shouhin_tachi) 70 | { 71 | if (pipes[3] == shouhin.btn) 72 | { 73 | int growtoken_cost = std::abs(shouhin.cost); 74 | if (shouhin.btn == "upgrade_backpack") shouhin.cost = backpack_cost; 75 | if ((_tab == 5) 76 | ? (growtoken == peer->slots.end() || growtoken->count < growtoken_cost) 77 | : peer->gems < shouhin.cost) 78 | { 79 | packet::create(*event.peer, false, 0, 80 | { 81 | "OnStorePurchaseResult", 82 | (_tab < 5) ? 83 | std::format("You can't afford `0{}``! You're `${}`` Gems short.", 84 | shouhin.name, shouhin.cost - peer->gems).c_str() : 85 | std::format("You can't afford `0{}``! You're `${}`` `2Growtokens`` short.", 86 | shouhin.name, (growtoken == peer->slots.end()) ? growtoken_cost : growtoken_cost - growtoken->count).c_str() 87 | }); 88 | return; 89 | } 90 | srand(std::time(0)); 91 | std::vector ids{}; 92 | if (shouhin.btn == "basic_splice") // @note source: https://growtopia.fandom.com/wiki/Basic_Splicing_Kit 93 | { 94 | shouhin.im.emplace_back(11, 10); 95 | ids = {3567, 2793, 57, 13, 17, 21, 101, 381, 1139}; // @note instead of iterating seeds with rarity 2 each time 96 | for (u_char i = 0; i < 10; ++i) 97 | shouhin.im.emplace_back(ids[rand() % ids.size()], 1); 98 | } 99 | else if (shouhin.btn == "rare_seed") // @note source: https://growtopia.fandom.com/wiki/Rare_Seed_Pack 100 | { 101 | for (auto &&[id, item] : items) 102 | if (item.type == type::SEED && item.rarity >= 13 && item.rarity <= 60) 103 | ids.emplace_back(id); 104 | for (u_char i = 0; i < 5; ++i) 105 | shouhin.im.emplace_back(ids[rand() % ids.size()], 1); 106 | } 107 | else if (shouhin.btn == "clothes_pack") // @note source: https://growtopia.fandom.com/wiki/Clothes_Pack 108 | { 109 | for (auto &&[id, item] : items) 110 | if (item.type == type::CLOTHING && item.rarity <= 10) 111 | ids.emplace_back(id); 112 | for (u_char i = 0; i < 3; ++i) 113 | shouhin.im.emplace_back(ids[rand() % ids.size()], 1); 114 | } 115 | else if (shouhin.btn == "rare_clothes_pack") // @note source: https://growtopia.fandom.com/wiki/Rare_Clothes_Pack 116 | { 117 | for (auto &&[id, item] : items) 118 | if (item.type == type::CLOTHING && item.rarity >= 11 && item.rarity <= 60) 119 | ids.emplace_back(id); 120 | for (u_char i = 0; i < 3; ++i) 121 | shouhin.im.emplace_back(ids[rand() % ids.size()], 1); 122 | } 123 | 124 | std::string received{}; 125 | for (std::pair &im : shouhin.im) 126 | { 127 | if (im.first == 9412) peer->slot_size += 10; // @note 9412 is the id for increase backpack sprite, but peer wont actually be given that item. 128 | else peer->emplace(slot(im.first, im.second)); 129 | received.append(std::format("{}, ", items[im.first].raw_name)); // @todo add green text to rare items, or something cool. 130 | } 131 | 132 | packet::create(*event.peer, false, 0, 133 | { 134 | "OnStorePurchaseResult", 135 | (_tab < 5) ? 136 | std::format( 137 | "You've purchased `0{}`` for `${}`` Gems.\nYou have `${}`` Gems left.\n\n`5Received: ```0{}``", 138 | shouhin.name, shouhin.cost, peer->gems -= shouhin.cost, received).c_str() : 139 | std::format( 140 | "You've purchased `0{}`` for `${}`` `2Growtokens``.\nYou have `${}`` `2Growtokens`` left.\n\n`5Received: ```0{}``", 141 | shouhin.name, growtoken_cost, growtoken->count -= growtoken_cost, received).c_str() 142 | }); 143 | inventory_visuals(event); 144 | on::SetBux(event); // @todo wasteful if peer is buying with growtokens 145 | 146 | break; 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /include/database/peer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | #include "items.hpp" 3 | #include "peer.hpp" 4 | #include "world.hpp" 5 | #include "on/SetClothing.hpp" 6 | 7 | #if defined(_MSC_VER) 8 | using namespace std::chrono; 9 | #else 10 | using namespace std::chrono::_V2; 11 | #endif 12 | 13 | short peer::emplace(slot s) 14 | { 15 | if (auto it = std::ranges::find_if(this->slots, [s](const slot &found) { return found.id == s.id; }); it != this->slots.end()) 16 | { 17 | short excess = std::max(0, (it->count + s.count) - 200); 18 | it->count = std::min(it->count + s.count, 200); 19 | if (it->count == 0) 20 | { 21 | item &item = items[it->id]; 22 | if (item.cloth_type != clothing::none) this->clothing[item.cloth_type] = 0; 23 | } 24 | return excess; 25 | } 26 | else this->slots.emplace_back(std::move(s)); // @note no such item in inventory, so we create a new entry. 27 | return 0; 28 | } 29 | 30 | void peer::add_xp(u_short value) 31 | { 32 | u_short &lvl = this->level.front(); 33 | u_short &xp = this->level.back() += value; // @note factor the new xp amount 34 | 35 | const u_short xp_formula = 50 * (lvl * lvl + 2); // @note credits: https://www.growtopiagame.com/forums/member/553046-kasete 36 | const u_short level_up = std::min(xp / xp_formula, 125 - lvl); 37 | 38 | lvl += level_up; 39 | xp -= level_up * xp_formula; 40 | } 41 | 42 | class peer_db { 43 | private: 44 | sqlite3 *db; 45 | 46 | void sqlite3_bind(sqlite3_stmt* stmt, int index, int value) 47 | { 48 | sqlite3_bind_int(stmt, index, value); 49 | } 50 | void sqlite3_bind(sqlite3_stmt* stmt, int index, const std::string& value) 51 | { 52 | sqlite3_bind_text(stmt, index, value.c_str(), -1, SQLITE_STATIC); 53 | } 54 | public: 55 | peer_db() { 56 | sqlite3_open("db/peers.db", &db); 57 | create_tables(); 58 | }~peer_db() { sqlite3_close(db); } 59 | 60 | void create_tables() 61 | { 62 | const char *sql = 63 | "CREATE TABLE IF NOT EXISTS peers (_n TEXT PRIMARY KEY, role INTEGER, gems INTEGER, lvl INTEGER, xp INTEGER);" 64 | "CREATE TABLE IF NOT EXISTS slots (_n TEXT, i INTEGER, c INTEGER, FOREIGN KEY(_n) REFERENCES peers(_n));"; 65 | 66 | sqlite3_exec(db, sql, nullptr, nullptr, nullptr); 67 | } 68 | 69 | template 70 | void execute(const char* sql, T binder) 71 | { 72 | sqlite3_stmt* stmt; 73 | if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) == SQLITE_OK) { 74 | binder(stmt); 75 | sqlite3_step(stmt); 76 | sqlite3_finalize(stmt); 77 | } 78 | } 79 | 80 | template 81 | void query(const char* sql, T &&fun, const std::string &name) 82 | { 83 | sqlite3_stmt* stmt; 84 | if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) == SQLITE_OK) 85 | { 86 | sqlite3_bind(stmt, 1, name); 87 | 88 | while (sqlite3_step(stmt) == SQLITE_ROW) 89 | { 90 | fun(stmt); 91 | } 92 | sqlite3_finalize(stmt); 93 | } 94 | } 95 | 96 | void begin_transaction() 97 | { 98 | sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr); 99 | } 100 | 101 | void commit() 102 | { 103 | sqlite3_exec(db, "COMMIT", nullptr, nullptr, nullptr); 104 | } 105 | }; 106 | 107 | peer& peer::read(const std::string& name) 108 | { 109 | peer_db db; 110 | 111 | db.query("SELECT role, gems, lvl, xp FROM peers WHERE _n = ?", [this](sqlite3_stmt* stmt) 112 | { 113 | this->role = static_cast(sqlite3_column_int(stmt, 0)); 114 | this->gems = sqlite3_column_int(stmt, 1); 115 | this->level[0] = static_cast(sqlite3_column_int(stmt, 2)); 116 | this->level[1] = static_cast(sqlite3_column_int(stmt, 3)); 117 | }, name); 118 | 119 | db.query("SELECT i, c FROM slots WHERE _n = ?", [this](sqlite3_stmt* stmt) 120 | { 121 | this->slots.emplace_back( 122 | sqlite3_column_int(stmt, 0), 123 | sqlite3_column_int(stmt, 1) 124 | ); 125 | }, name); 126 | 127 | return *this; 128 | } 129 | 130 | peer::~peer() 131 | { 132 | if (ltoken[0].empty()) return; 133 | 134 | peer_db db; 135 | db.begin_transaction(); 136 | 137 | db.execute("REPLACE INTO peers (_n, role, gems, lvl, xp) VALUES (?, ?, ?, ?, ?)", [this](sqlite3_stmt* stmt) 138 | { 139 | sqlite3_bind_text(stmt, 1, this->ltoken[0].c_str(), -1, SQLITE_STATIC); 140 | sqlite3_bind_int(stmt, 2, this->role); 141 | sqlite3_bind_int(stmt, 3, this->gems); 142 | sqlite3_bind_int(stmt, 4, this->level[0]); 143 | sqlite3_bind_int(stmt, 5, this->level[1]); 144 | }); 145 | 146 | db.execute("DELETE FROM slots WHERE _n = ?", [this](auto stmt) { 147 | sqlite3_bind_text(stmt, 1, this->ltoken[0].c_str(), -1, SQLITE_STATIC); 148 | }); 149 | 150 | for (const ::slot &slot : this->slots) 151 | { 152 | if ((slot.id == 18 || slot.id == 32) || slot.count <= 0) continue; 153 | db.execute("INSERT INTO slots (_n, i, c) VALUES (?, ?, ?)", [this, &slot](sqlite3_stmt* stmt) 154 | { 155 | sqlite3_bind_text(stmt, 1, this->ltoken[0].c_str(), -1, SQLITE_STATIC); 156 | sqlite3_bind_int(stmt, 2, slot.id); 157 | sqlite3_bind_int(stmt, 3, slot.count); 158 | }); 159 | } 160 | db.commit(); 161 | } 162 | 163 | std::unordered_map> _peer; 164 | 165 | ENetHost *server; 166 | 167 | std::vector peers(ENetEvent event, peer_condition condition, std::function fun) 168 | { 169 | std::vector _peers{}; 170 | _peers.reserve(server->peerCount); 171 | 172 | for (ENetPeer &peer : std::span(server->peers, server->peerCount)) 173 | if (peer.state == ENET_PEER_STATE_CONNECTED) // @todo handle peers who haven't been allocated in _peer 174 | { 175 | if (condition == peer_condition::PEER_SAME_WORLD) 176 | { 177 | auto &recent_worlds = _peer[event.peer]->recent_worlds; 178 | if (_peer[&peer]->netid == 0 || (_peer[&peer]->recent_worlds.back() != recent_worlds.back())) continue; 179 | } 180 | fun(peer); 181 | _peers.push_back(&peer); 182 | } 183 | 184 | return _peers; 185 | } 186 | 187 | void safe_disconnect_peers(int signal) 188 | { 189 | for (ENetPeer &p : std::span(server->peers, server->peerCount)) 190 | if (p.state == ENET_PEER_STATE_CONNECTED) 191 | { 192 | enet_peer_disconnect(&p, 0); 193 | } 194 | 195 | enet_host_destroy(server); 196 | enet_deinitialize(); 197 | } 198 | 199 | state get_state(const std::vector &&packet) 200 | { 201 | const int *_4bit = reinterpret_cast(packet.data()); 202 | const float *_4bit_f = reinterpret_cast(packet.data()); 203 | return state{ 204 | .type = _4bit[0], 205 | .netid = _4bit[1], 206 | .uid = _4bit[2], 207 | .peer_state = _4bit[3], 208 | .count = _4bit_f[4], 209 | .id = _4bit[5], 210 | .pos = {_4bit_f[6], _4bit_f[7]}, 211 | .speed = {_4bit_f[8], _4bit_f[9]}, 212 | 213 | .punch = ::pos{_4bit[11], _4bit[12]} 214 | }; 215 | } 216 | 217 | std::vector compress_state(const state &s) 218 | { 219 | std::vector data(sizeof(::state), std::byte{ 00 }); 220 | int *_4bit = reinterpret_cast(data.data()); 221 | float *_4bit_f = reinterpret_cast(data.data()); 222 | _4bit[0] = s.type; 223 | _4bit[1] = s.netid; 224 | _4bit[2] = s.uid; 225 | _4bit[3] = s.peer_state; 226 | _4bit_f[4] = s.count; 227 | _4bit[5] = s.id; 228 | _4bit_f[6] = s.pos[0]; 229 | _4bit_f[7] = s.pos[1]; 230 | _4bit_f[8] = s.speed[0]; 231 | _4bit_f[9] = s.speed[1]; 232 | 233 | _4bit[11] = s.punch.x; 234 | _4bit[12] = s.punch.y; 235 | return data; 236 | } 237 | 238 | void inventory_visuals(ENetEvent &event) 239 | { 240 | auto &peer = _peer[event.peer]; 241 | std::size_t size = peer->slots.size(); 242 | std::vector data(66zu + (size * sizeof(int))); 243 | 244 | data[0zu] = PACKET_CREATE; 245 | data[4zu] = std::byte{ 0x09 }; // @note PACKET_SEND_INVENTORY_STATE 246 | *reinterpret_cast(&data[8zu]) = peer->netid; 247 | data[16zu] = PACKET_STATE; 248 | *reinterpret_cast(&data[58zu]) = std::byteswap(peer->slot_size); 249 | *reinterpret_cast(&data[62zu]) = std::byteswap(size); 250 | int *slot_ptr = reinterpret_cast(&data[66zu]); 251 | for (const ::slot &slot : peer->slots) 252 | *slot_ptr++ = slot.id | (slot.count & 0xff) << 16; 253 | 254 | enet_peer_send(event.peer, 0, enet_packet_create(data.data(), data.size(), ENET_PACKET_FLAG_RELIABLE)); 255 | } 256 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------