init commit. I should have done it a while ago though

This commit is contained in:
Zergling_man 2025-06-23 20:49:20 +10:00
commit b0e5e89126
25 changed files with 910 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
# Godot 4+ specific ignores
.godot/
/android/
src/*.os
bin
godot-cpp

4
README Normal file
View File

@ -0,0 +1,4 @@
You must `scons` to create ./bin/whatever before running this
Deps: Godot >=4.0 (probably)
Makedeps: sconstruct, godot-cpp (which should be symlinked from .)

43
SConstruct Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env python
import os
import sys
env = SConscript("godot-cpp/SConstruct")
# For reference:
# - CCFLAGS are compilation flags shared between C and C++
# - CFLAGS are for C-specific compilation flags
# - CXXFLAGS are for C++-specific compilation flags
# - CPPFLAGS are for pre-processor flags
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags
# tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=["src/"])
sources = Glob("src/*.cpp")
if env["platform"] == "macos":
library = env.SharedLibrary(
"bin/libgdcharacter.{}.{}.framework/libgdexample.{}.{}".format(
env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
elif env["platform"] == "ios":
if env["ios_simulator"]:
library = env.StaticLibrary(
"bin/libgdcharacter.{}.{}.simulator.a".format(env["platform"], env["target"]),
source=sources,
)
else:
library = env.StaticLibrary(
"bin/libgdcharacter.{}.{}.a".format(env["platform"], env["target"]),
source=sources,
)
else:
library = env.SharedLibrary(
"bin/libgdcharacter{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)

6
build_scons.sh Normal file
View File

@ -0,0 +1,6 @@
# Debug
scons
# Release
scons target=template_release
scons platform=win target=template_release

1
icon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 994 B

37
icon.svg.import Normal file
View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://5efnxljgii3e"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

82
lobby.gd Normal file
View File

@ -0,0 +1,82 @@
extends Control
signal game_start
var pname=""
var players={}
var PLAYER_SCENE=load("res://player.tscn")
func _ready():
multiplayer.peer_connected.connect(add_player)
multiplayer.peer_disconnected.connect(remove_player)
func start(id,given_name):
push_warning(id) # Helps identify windows for print() output, but push_warning is more convenient anyway.
pname=given_name # Why can't I have push_notice/push_debug?
add_player(id)
show()
# ESSENTIAL TENETS:
# The multiplayer authority of spawning basically always resides with 1.
# Whether this is tied to the authority of the spawner or its target node, I don't know, but it doesn't really matter.
# THEREFORE, any local data you want to pick up has to be fetched after RPC handoff.
# In addition: Any properties set on an object in the frame it's created probably won't sync or persist
# use call_deferred or await get_tree().process_frame to fix this.
func add_player(pid):
players[pid]={}
var a
if multiplayer.get_unique_id()==1:
a=PLAYER_SCENE.instantiate()
a.name=str(pid)
$fuck_layouts/player_list.add_child(a)
else:
a=$fuck_layouts/player_list.find_child(str(pid),false,false)
while a==null:
await get_tree().process_frame
a=$fuck_layouts/player_list.find_child(str(pid),false,false)
a.set_multiplayer_authority(pid)
a.get_node('PName').text=pname # This tries to force local name on every node but sync will fix it after
func remove_player(pid):
players.erase(pid)
# Kinda works? Sometimes posts errors from other clients but still behaves correctly so idk
$fuck_layouts/player_list.remove_child($fuck_layouts/player_list.get_node(str(pid)))
func _on_send_message_pressed(message=""):
var box=$fuck_layouts/menu_shiz/chats/shitpost/input
if message=="": message=box.text
rpc("receive_message",pname,message)
box.text=""
@rpc("any_peer","call_local")
func receive_message(pid,message):
var a=Label.new()
a.text=str(pid)+": "+message
var scroll=$fuck_layouts/menu_shiz/chats/elder
scroll.get_node('messages').add_child(a)
# I don't really understand this magic number but it works on my machine.
# The offset is actually 128px, but this means it should grab even if you only see ~3/4 of the last message
var bump=scroll.scroll_vertical+134>scroll.get_v_scroll_bar().max_value
await get_tree().process_frame # This seems to not work if the window doesn't have focus.
# Not going to bother figuring it out unless it's important for something else.
if bump: scroll.ensure_control_visible(a)
func _start_clicked():
var pid=0
for child in $fuck_layouts/player_list.get_children(true):
if child.name=='player_spawner': continue
pid=child.get_multiplayer_authority()
players[pid]['name']=child.get_node('PName').text
players[pid]['class']=child.get_node('PChar/Class').selected
if players.values().any(func(x):return x=={} or x['class']==-1):
receive_message('System','Not all players have finalised their options')
return
rpc("gamestart",players)
@rpc("any_peer","call_local")
func gamestart(players):
emit_signal('game_start',players)
hide()
func _idk_clicked():
pass

1
lobby.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://uwpqjqvde2ot

50
menu.gd Normal file
View File

@ -0,0 +1,50 @@
extends Control
const PORT=60001
signal lobby_join
func _ready():
# Start paused.
# This actually breaks the buttons lol
#get_tree().paused = true
# You can save bandwidth by disabling server relay and peer notifications.
#multiplayer.server_relay = false
# Automatically start the server in headless mode.
if DisplayServer.get_name() == "headless":
# Should attempt to pull port from config file
print("Automatically starting dedicated server.")
_on_host_pressed.call_deferred(true)
func _on_host_pressed(headless=false):
# Start as server.
var peer = ENetMultiplayerPeer.new()
var port = $Net/Options/port.text
if port=="": port=PORT
peer.create_server(port)
if peer.get_connection_status() == MultiplayerPeer.CONNECTION_DISCONNECTED:
OS.alert("Failed to start multiplayer server.")
return
multiplayer.multiplayer_peer = peer
start_game(headless)
func _on_join_pressed():
# Start as client.
var port = $Net/Options/port.text
if port=="": port=PORT
var txt : String = $Net/Options/address.text
if txt == "":
OS.alert("Need a remote to connect to.")
return
var peer = ENetMultiplayerPeer.new()
peer.create_client(txt, port)
if peer.get_connection_status() == MultiplayerPeer.CONNECTION_DISCONNECTED:
OS.alert("Failed to start multiplayer client.")
return
multiplayer.multiplayer_peer = peer
start_game() # Can't run a headless client lol what are you trying to bot the game
func start_game(headless=false):
if headless: return
emit_signal("lobby_join",multiplayer.get_unique_id(),$Net/pname/Name.text)
hide()

1
menu.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://baxkcpwuj61it

39
player.tscn Normal file
View File

@ -0,0 +1,39 @@
[gd_scene load_steps=2 format=3 uid="uid://b25q27admm4le"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_sh265"]
properties/0/path = NodePath("PName:text")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath("PChar/Class:selected")
properties/1/spawn = true
properties/1/replication_mode = 1
[node name="Player" type="VBoxContainer"]
offset_right = 40.0
offset_bottom = 40.0
size_flags_horizontal = 3
[node name="PName" type="Label" parent="."]
layout_mode = 2
[node name="PChar" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="Class" type="OptionButton" parent="PChar"]
layout_mode = 2
item_count = 6
popup/item_0/text = "Pyromancer"
popup/item_0/id = 0
popup/item_1/text = "Rogue"
popup/item_1/id = 1
popup/item_2/text = "Spelunker"
popup/item_2/id = 2
popup/item_3/text = "Acrobat"
popup/item_3/id = 3
popup/item_4/text = "Paladin"
popup/item_4/id = 4
popup/item_5/text = "Medic"
popup/item_5/id = 5
[node name="sonq" type="MultiplayerSynchronizer" parent="."]
replication_config = SubResource("SceneReplicationConfig_sh265")

52
project.godot Normal file
View File

@ -0,0 +1,52 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="amb-crawl"
run/main_scene="res://ui.tscn"
config/features=PackedStringArray("4.4", "GL Compatibility")
config/icon="res://icon.svg"
[dotnet]
project/assembly_name="net-test"
[input]
move_up={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":85,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_down={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":69,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":78,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":73,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
[rendering]
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"

58
src/controller.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "controller.h"
using namespace godot;
void Controller::_bind_methods()
{
ClassDB::bind_method(D_METHOD("get_flags"), &Controller::get_flags);
ClassDB::bind_method(D_METHOD("set_flags","p_flags"), &Controller::set_flags);
ADD_PROPERTY(PropertyInfo(Variant::INT, "flags"), "set_flags", "get_flags");
ClassDB::bind_method(D_METHOD("get_target"), &Controller::get_target);
ClassDB::bind_method(D_METHOD("set_target","p_target"), &Controller::set_target);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "target", PROPERTY_HINT_RESOURCE_TYPE, "Vector2"), "set_target", "get_target");
}
Controller::Controller()
{
flags=0;
target=Vector2(0,0);
}
Controller::~Controller(){}
void Controller::_process(double delta)
{
if (get_multiplayer()->get_unique_id()!=get_multiplayer_authority()) return;
// Kinda janky but this might come in handy later
target=parent->get_global_mouse_position();
}
void Controller::_enter_tree()
{
set_root_path(NodePath("."));
Ref<SceneReplicationConfig> conf=memnew(SceneReplicationConfig);
set_replication_config(conf);
conf->add_property(":flags");
conf->add_property(":target");
}
void Controller::_unhandled_key_input(const Ref<InputEvent> &p_event)
{
if (get_multiplayer()->get_unique_id()!=get_multiplayer_authority()) return;
UtilityFunctions::print("pre ",flags);
//これ嫌い
if (p_event->is_action_pressed("move_up",false,true)) flags|=1;
if (p_event->is_action_released("move_up",true)) flags&=-2;
if (p_event->is_action_pressed("move_down",false,true)) flags|=2;
if (p_event->is_action_released("move_down",true)) flags&=-3;
if (p_event->is_action_pressed("move_left",false,true)) flags|=4;
if (p_event->is_action_released("move_left",true)) flags&=-5;
if (p_event->is_action_pressed("move_right",false,true)) flags|=8;
if (p_event->is_action_released("move_right",true)) flags&=-9;
//Viewport.set_input_as_handled(); // I have no idea how this figures out which input to flag as handled.
}
void Controller::set_flags(const int p_flags) { flags=p_flags; }
int Controller::get_flags() const { return flags; }
void Controller::set_target(const Vector2 p_target) { target=p_target; }
Vector2 Controller::get_target() const { return target; }

34
src/controller.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef GDCONTROLLER_H
#define GDCONTROLLER_H
#include <godot_cpp/classes/multiplayer_synchronizer.hpp>
// YOU MAY GET MYSTERIOUS "INVALID USE OF INCOMPLETE TYPE" ERRORS IF YOU DO NOT INCLUDE THE THINGS YOU NEED, BECAUSE THEY MIGHT BE BRIEFLY DEFINED IN OTHER THINGS.
#include <godot_cpp/classes/scene_replication_config.hpp>
#include <godot_cpp/classes/multiplayer_api.hpp>
#include <godot_cpp/classes/input_event.hpp>
#include <godot_cpp/classes/canvas_item.hpp>
namespace godot
{
class Controller : public MultiplayerSynchronizer
{
GDCLASS(Controller,MultiplayerSynchronizer)
protected:
static void _bind_methods();
public:
int flags;
Vector2 target;
CanvasItem *parent;
Controller();
~Controller();
void _process(double delta) override;
void _enter_tree() override;
void _unhandled_key_input(const Ref<InputEvent> &p_event);
// Garbage
void set_flags(const int p_flags);
int get_flags() const;
void set_target(const Vector2 p_target);
Vector2 get_target() const;
};
}
#endif

35
src/example.cpp.no Normal file
View File

@ -0,0 +1,35 @@
#include "example.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void Example::_bind_methods()
{
ClassDB::bind_method(D_METHOD("get_amplitude"), &Example::get_amplitude);
ClassDB::bind_method(D_METHOD("set_amplitude","p_amplitude"), &Example::set_amplitude);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude");
ClassDB::bind_method(D_METHOD("get_speed"), &Example::get_speed);
ClassDB::bind_method(D_METHOD("set_speed","p_speed"), &Example::set_speed);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE,"0,20,0.01"), "set_speed", "get_speed");
}
Example::Example()
{
time_passed=0.0;
amplitude=10.0;
speed=1.0;
}
Example::~Example(){}
void Example::_process(double delta)
{
time_passed+=speed*delta;
Vector2 new_position=Vector2(amplitude+(amplitude*sin(time_passed*2.0)),amplitude+(amplitude*cos(time_passed*1.5)));
set_position(new_position);
}
void Example::set_amplitude(const double p_amplitude) { amplitude=p_amplitude; }
double Example::get_amplitude() const { return amplitude; }
void Example::set_speed(const double p_speed) { speed=p_speed; }
double Example::get_speed() const { return speed; }

28
src/example.h.no Normal file
View File

@ -0,0 +1,28 @@
#ifndef GDEXAMPLE_H
#define GDEXAMPLE_H
#include <godot_cpp/classes/sprite2d.hpp>
namespace godot
{
class Example : public Sprite2D
{
GDCLASS(Example, Sprite2D)
private:
double time_passed;
double amplitude;
double speed;
protected:
static void _bind_methods();
public:
Example();
~Example();
void _process(double delta) override;
void set_amplitude(const double p_amplitude);
double get_amplitude() const;
void set_speed(const double p_speed);
double get_speed() const;
};
}
#endif

45
src/game.cpp Normal file
View File

@ -0,0 +1,45 @@
#include "game.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void Game::_bind_methods()
{
ClassDB::bind_method(D_METHOD("start","players"),&Game::start);
ClassDB::bind_method(D_METHOD("kyaraspawn","data"),&Game::kyaraspawn);
}
Game::Game()
{
spawn=memnew(MultiplayerSpawner);
spawn->set_name("_spawn");
spawn->set_spawn_function(callable_mp(this, &Game::kyaraspawn));
spawn->set_spawn_path("..");
add_child(spawn,false,INTERNAL_MODE_BACK);
}
Game::~Game(){}
void Game::start(const Dictionary &players)
{
show();
if (get_multiplayer()->get_unique_id()!=1) return;
Array keys=players.keys();
for (int i=0; i<keys.size(); i++)
{
static_cast<Dictionary>(players[keys[i]])["pid"]=keys[i];
UtilityFunctions::print(get_multiplayer()->get_unique_id()," ",keys[i]," ",players[keys[i]]," ",static_cast<Dictionary>(players[keys[i]])["name"]);
spawn->spawn(players[keys[i]]);
}
}
Node* Game::kyaraspawn(const Variant &data)
{
Dictionary dat=static_cast<Dictionary>(data);
UtilityFunctions::print(get_multiplayer()->get_unique_id()," ",data);
Character* kya=memnew(Character);
kya->set_name(dat["name"]);
kya->multiplayerowner=dat["pid"];
kya->set_position(Vector2(50,50));
kya->set_texture(ImageTexture::create_from_image(Image::load_from_file("res://icon.svg")));
return kya;
}

29
src/game.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef GDGAME_H
#define GDGAME_H
#include <godot_cpp/classes/node2d.hpp>
#include "kyara.h"
#include <godot_cpp/classes/multiplayer_api.hpp>
#include <godot_cpp/classes/multiplayer_spawner.hpp>
#include <godot_cpp/classes/image_texture.hpp>
#include <godot_cpp/classes/image.hpp>
namespace godot
{
class Game : public Node2D
{
GDCLASS(Game, Node2D)
private:
MultiplayerSpawner *spawn;
protected:
static void _bind_methods();
public:
Game();
~Game();
void start(const Dictionary &players);
Node* kyaraspawn(const Variant &data);
};
}
#endif

81
src/kyara.cpp Normal file
View File

@ -0,0 +1,81 @@
#include "kyara.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void Character::_bind_methods()
{
ClassDB::bind_method(D_METHOD("get_balance_radius"), &Character::get_balance_radius);
ClassDB::bind_method(D_METHOD("set_balance_radius","p_balance_radius"), &Character::set_balance_radius);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "balance_radius"), "set_balance_radius", "get_balance_radius");
ClassDB::bind_method(D_METHOD("get_speed"), &Character::get_speed);
ClassDB::bind_method(D_METHOD("set_speed","p_speed"), &Character::set_speed);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE,"0,20,0.01"), "set_speed", "get_speed");
ClassDB::bind_method(D_METHOD("get_texture"), &Character::get_texture);
ClassDB::bind_method(D_METHOD("set_texture","p_texture"), &Character::set_texture);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
}
Character::Character()
{
set_motion_mode(MOTION_MODE_FLOATING);
speed=1.0;
balance_radius=64.0;
face=memnew(Sprite2D);
face->set_name("_face");
add_child(face,false,INTERNAL_MODE_BACK);
input=memnew(Controller);
input->set_name("_input");
input->parent=this;
add_child(input,false,INTERNAL_MODE_BACK);
sync=memnew(MultiplayerSynchronizer);
sync->set_name("_sync");
add_child(sync,false,INTERNAL_MODE_BACK);
shape=memnew(CollisionShape2D);
shape->set_name("_shape");
add_child(shape,false,INTERNAL_MODE_BACK);
}
Character::~Character(){}
void Character::_process(double delta)
{
// これも嫌い
if (input->flags&1) move(0.0,-speed);
if (input->flags&2) move(0.0,speed);
if (input->flags&4) move(-speed,0.0);
if (input->flags&8) move(speed,0.0);
look_at(input->target);
// Not sure if I should do this. Issues could occur if I'm wrong either side.
//CharacterBody2D::_process(delta);
}
void Character::_ready()
{
set_motion_mode(MOTION_MODE_FLOATING);
}
void Character::_enter_tree()
{
Ref<SceneReplicationConfig> conf=memnew(SceneReplicationConfig);
conf->add_property(":rotation");
conf->add_property(":position");
sync->set_replication_config(conf);
input->set_multiplayer_authority(multiplayerowner);
}
void Character::move(double x,double y)
{
// Collision detection needs to go in here, as well as adjusting and displaying balance radius, buncha shit
set_position(get_position()+Vector2(x,y));
}
void Character::set_balance_radius(const double p_balance_radius) { balance_radius=p_balance_radius; }
double Character::get_balance_radius() const { return balance_radius; }
void Character::set_speed(const double p_speed) { speed=p_speed; }
double Character::get_speed() const { return speed; }
void Character::set_texture(const Ref<Texture2D> &p_texture) { face->set_texture(p_texture); }
Ref<Texture2D> Character::get_texture() const { return face->get_texture(); }

51
src/kyara.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef GDKYARA_H
#define GDKYARA_H
#include <godot_cpp/classes/character_body2d.hpp>
// Children:
#include "controller.h"
#include <godot_cpp/classes/collision_shape2d.hpp>
#include <godot_cpp/classes/sprite2d.hpp>
#include <godot_cpp/classes/multiplayer_synchronizer.hpp>
// Grandchildren:
#include <godot_cpp/classes/circle_shape2d.hpp>
// YOU MAY GET MYSTERIOUS "INVALID USE OF INCOMPLETE TYPE" ERRORS IF YOU DO NOT INCLUDE THE THINGS YOU NEED, BECAUSE THEY MIGHT BE BRIEFLY DEFINED IN OTHER THINGS.
#include <godot_cpp/classes/scene_replication_config.hpp>
namespace godot
{
class Character : public CharacterBody2D
{
GDCLASS(Character, CharacterBody2D)
private:
double speed;
double balance_radius;
void move(double x,double y);
Sprite2D *face;
Controller *input;
MultiplayerSynchronizer *sync;
CollisionShape2D *shape;
protected:
static void _bind_methods();
public:
Character();
~Character();
void _process(double delta) override;
void _ready() override;
void _enter_tree() override;
int multiplayerowner;
// Garbage
void set_balance_radius(const double p_balance_radius);
double get_balance_radius() const;
void set_speed(const double p_speed);
double get_speed() const;
// This garbage ripped straight from sprite2d because I basically just want to pass it through.
// I don't really need to (I can just make the sprite public) but it's good practice
// (By good practice I mean this cost me at least an hour of debugging const Ref<>)
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
};
}
#endif

9
src/nodespawner.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "nodespawner.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void NodeSpawner::_bind_methods()
{
}

21
src/nodespawner.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef GDNODESPAWNER_H
#define GDNODESPAWNER_H
#include <godot_cpp/classes/multiplayer_spawner.hpp>
// Probably won't need this.
//#include <godot_cpp/classes/multiplayer_api.hpp>
namespace godot
{
class NodeSpawner : public MultiplayerSpawner
{
GDCLASS(NodeSpawner,MultiplayerSpawner)
private:
String *spawnable_nodes;
protected:
static void _bind_methods();
public:
};
}
#endif

37
src/register_types.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "register_types.h"
#include "kyara.h"
#include "controller.h"
#include "game.h"
#include "nodespawner.h"
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
using namespace godot;
void initialize_character_module(ModuleInitializationLevel p_level)
{
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; }
GDREGISTER_RUNTIME_CLASS(Character);
GDREGISTER_RUNTIME_CLASS(Controller);
GDREGISTER_RUNTIME_CLASS(Game);
GDREGISTER_RUNTIME_CLASS(NodeSpawner);
}
void uninitialize_character_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; }
}
extern "C"
{
GDExtensionBool GDE_EXPORT character_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization)
{
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_character_module);
init_obj.register_terminator(uninitialize_character_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}

10
src/register_types.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef CHARACTER_REGISTER_TYPES_H
#define CHARACTER_REGISTER_TYPES_H
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void initialize_character_module(ModuleInitializationLevel p_level);
void uninitialize_character_module(ModuleInitializationLevel p_level);
#endif

150
ui.tscn Normal file
View File

@ -0,0 +1,150 @@
[gd_scene load_steps=3 format=3 uid="uid://1qpp4ng383lf"]
[ext_resource type="Script" uid="uid://baxkcpwuj61it" path="res://menu.gd" id="1_fyqef"]
[ext_resource type="Script" uid="uid://uwpqjqvde2ot" path="res://lobby.gd" id="2_m6e0p"]
[node name="scene" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="main_menu" type="Control" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_fyqef")
[node name="Net" type="VBoxContainer" parent="main_menu"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -130.5
offset_top = -64.0
offset_right = 130.5
offset_bottom = 64.0
grow_horizontal = 2
grow_vertical = 2
[node name="Direct" type="Label" parent="main_menu/Net"]
layout_mode = 2
text = "Direct connect:"
[node name="Options" type="HBoxContainer" parent="main_menu/Net"]
layout_mode = 2
[node name="address" type="LineEdit" parent="main_menu/Net/Options"]
custom_minimum_size = Vector2(96, 0)
layout_mode = 2
placeholder_text = "127.0.0.1"
[node name="port" type="LineEdit" parent="main_menu/Net/Options"]
layout_mode = 2
placeholder_text = "60001"
[node name="pname" type="HBoxContainer" parent="main_menu/Net"]
layout_mode = 2
[node name="Nickname" type="Label" parent="main_menu/Net/pname"]
layout_mode = 2
text = "Nickname:"
[node name="Name" type="LineEdit" parent="main_menu/Net/pname"]
custom_minimum_size = Vector2(128, 0)
layout_mode = 2
[node name="buttons" type="HBoxContainer" parent="main_menu/Net"]
layout_mode = 2
[node name="Host" type="Button" parent="main_menu/Net/buttons"]
layout_mode = 2
text = "Host"
[node name="Join" type="Button" parent="main_menu/Net/buttons"]
layout_mode = 2
text = "Join"
[node name="host_note" type="Label" parent="main_menu/Net/buttons"]
layout_mode = 2
text = "(host ignores address)"
[node name="Lobby" type="Control" parent="."]
visible = false
layout_mode = 1
anchors_preset = 0
script = ExtResource("2_m6e0p")
[node name="fuck_layouts" type="VBoxContainer" parent="Lobby"]
layout_mode = 0
offset_right = 516.0
offset_bottom = 167.0
[node name="menu_shiz" type="HBoxContainer" parent="Lobby/fuck_layouts"]
layout_mode = 2
[node name="chats" type="VBoxContainer" parent="Lobby/fuck_layouts/menu_shiz"]
layout_mode = 2
[node name="elder" type="ScrollContainer" parent="Lobby/fuck_layouts/menu_shiz/chats"]
custom_minimum_size = Vector2(512, 128)
layout_mode = 2
[node name="messages" type="VBoxContainer" parent="Lobby/fuck_layouts/menu_shiz/chats/elder"]
layout_mode = 2
[node name="shitpost" type="HBoxContainer" parent="Lobby/fuck_layouts/menu_shiz/chats"]
custom_minimum_size = Vector2(512, 0)
layout_mode = 2
[node name="input" type="LineEdit" parent="Lobby/fuck_layouts/menu_shiz/chats/shitpost"]
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "ni-"
keep_editing_on_text_submit = true
[node name="send_message" type="Button" parent="Lobby/fuck_layouts/menu_shiz/chats/shitpost"]
layout_mode = 2
text = "Shitpost"
[node name="buttons" type="VBoxContainer" parent="Lobby/fuck_layouts/menu_shiz"]
layout_mode = 2
[node name="start" type="Button" parent="Lobby/fuck_layouts/menu_shiz/buttons"]
layout_mode = 2
text = "Start"
[node name="leave" type="Button" parent="Lobby/fuck_layouts/menu_shiz/buttons"]
layout_mode = 2
text = "Leave"
[node name="idk" type="Button" parent="Lobby/fuck_layouts/menu_shiz/buttons"]
layout_mode = 2
text = "idk"
[node name="player_list" type="HBoxContainer" parent="Lobby/fuck_layouts"]
layout_mode = 2
[node name="player_spawner" type="MultiplayerSpawner" parent="Lobby/fuck_layouts/player_list"]
_spawnable_scenes = PackedStringArray("uid://b25q27admm4le")
spawn_path = NodePath("..")
[node name="Game" type="Game" parent="."]
[connection signal="lobby_join" from="main_menu" to="Lobby" method="start"]
[connection signal="pressed" from="main_menu/Net/buttons/Host" to="main_menu" method="_on_host_pressed"]
[connection signal="pressed" from="main_menu/Net/buttons/Join" to="main_menu" method="_on_join_pressed"]
[connection signal="game_start" from="Lobby" to="Game" method="start"]
[connection signal="text_submitted" from="Lobby/fuck_layouts/menu_shiz/chats/shitpost/input" to="Lobby" method="_on_send_message_pressed"]
[connection signal="pressed" from="Lobby/fuck_layouts/menu_shiz/chats/shitpost/send_message" to="Lobby" method="_on_send_message_pressed"]
[connection signal="pressed" from="Lobby/fuck_layouts/menu_shiz/buttons/start" to="Lobby" method="_start_clicked"]
[connection signal="pressed" from="Lobby/fuck_layouts/menu_shiz/buttons/idk" to="Lobby" method="_idk_clicked"]