init commit. I should have done it a while ago though
This commit is contained in:
commit
b0e5e89126
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
/android/
|
||||
src/*.os
|
||||
bin
|
||||
godot-cpp
|
4
README
Normal file
4
README
Normal 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
43
SConstruct
Normal 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
6
build_scons.sh
Normal file
@ -0,0 +1,6 @@
|
||||
# Debug
|
||||
scons
|
||||
|
||||
# Release
|
||||
scons target=template_release
|
||||
scons platform=win target=template_release
|
1
icon.svg
Normal file
1
icon.svg
Normal 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
37
icon.svg.import
Normal 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
82
lobby.gd
Normal 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
1
lobby.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://uwpqjqvde2ot
|
50
menu.gd
Normal file
50
menu.gd
Normal 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
1
menu.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://baxkcpwuj61it
|
39
player.tscn
Normal file
39
player.tscn
Normal 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
52
project.godot
Normal 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
58
src/controller.cpp
Normal 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
34
src/controller.h
Normal 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
35
src/example.cpp.no
Normal 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
28
src/example.h.no
Normal 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
45
src/game.cpp
Normal 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
29
src/game.h
Normal 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
81
src/kyara.cpp
Normal 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
51
src/kyara.h
Normal 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
9
src/nodespawner.cpp
Normal 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
21
src/nodespawner.h
Normal 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
37
src/register_types.cpp
Normal 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
10
src/register_types.h
Normal 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
150
ui.tscn
Normal 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"]
|
Loading…
x
Reference in New Issue
Block a user