Skip to content

Commit 7704cb5

Browse files
committed
Initial commit
0 parents  commit 7704cb5

18 files changed

Lines changed: 836 additions & 0 deletions

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Visual Studio 2015 user specific files
2+
.vs/
3+
4+
# Compiled Object files
5+
*.slo
6+
*.lo
7+
*.o
8+
*.obj
9+
10+
# Precompiled Headers
11+
*.gch
12+
*.pch
13+
14+
# Compiled Dynamic libraries
15+
*.so
16+
*.dylib
17+
*.dll
18+
19+
# Fortran module files
20+
*.mod
21+
22+
# Compiled Static libraries
23+
*.lai
24+
*.la
25+
*.a
26+
*.lib
27+
28+
# Executables
29+
*.exe
30+
*.out
31+
*.app
32+
*.ipa
33+
34+
# These project files can be generated by the engine
35+
*.xcodeproj
36+
*.xcworkspace
37+
*.sln
38+
*.suo
39+
*.opensdf
40+
*.sdf
41+
*.VC.db
42+
*.VC.opendb
43+
44+
# Precompiled Assets
45+
SourceArt/**/*.png
46+
SourceArt/**/*.tga
47+
48+
# Binary Files
49+
Binaries/*
50+
Plugins/**/Binaries/*
51+
52+
# Builds
53+
Build/*
54+
55+
# Whitelist PakBlacklist-<BuildConfiguration>.txt files
56+
!Build/*/
57+
Build/*/**
58+
!Build/*/PakBlacklist*.txt
59+
60+
# Don't ignore icon files in Build
61+
!Build/**/*.ico
62+
63+
# Built data for maps
64+
*_BuiltData.uasset
65+
66+
# Configuration files generated by the Editor
67+
Saved/*
68+
69+
# Compiled source files for the engine to use
70+
Intermediate/*
71+
Plugins/**/Intermediate/*
72+
73+
# Cache files for the editor to use
74+
DerivedDataCache/*

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Cutter-H
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"FileVersion": 3,
3+
"Version": 1,
4+
"VersionName": "1.0",
5+
"FriendlyName": "ReplicatedDrawingWidgetPlugin",
6+
"Description": "A widget that replicates a user's drawing for all other users.",
7+
"Category": "Other",
8+
"CreatedBy": "Cutter H",
9+
"CreatedByURL": "",
10+
"DocsURL": "",
11+
"MarketplaceURL": "",
12+
"SupportURL": "",
13+
"CanContainContent": true,
14+
"IsBetaVersion": false,
15+
"IsExperimentalVersion": false,
16+
"Installed": false,
17+
"Modules": [
18+
{
19+
"Name": "ReplicatedDrawingWidgetPlugin",
20+
"Type": "Runtime",
21+
"LoadingPhase": "Default"
22+
}
23+
]
24+
}

Resources/Icon128.png

12.4 KB
Loading
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
// Fill out your copyright notice in the Description page of Project Settings.
2+
3+
4+
#include "ReplicatedCanvasWidgetBase.h"
5+
6+
#include "EngineUtils.h"
7+
#include "Blueprint/WidgetBlueprintLibrary.h"
8+
#include "Blueprint/WidgetTree.h"
9+
#include "CanvasHelpers/CanvasPlayerStateHelper.h"
10+
#include "CanvasHelpers/ReplicatedCanvasManager.h"
11+
#include "CanvasHelpers/WorldCanvasSubsystem.h"
12+
#include "Components/Border.h"
13+
#include "Components/Overlay.h"
14+
#include "Components/OverlaySlot.h"
15+
#include "GameFramework/PlayerState.h"
16+
#include "Kismet/GameplayStatics.h"
17+
18+
19+
void UReplicatedCanvasWidgetBase::DrawLines(FPaintContext& context) const{
20+
for (const FCanvasLineData& line : LineData) {
21+
if(ShouldDrawLine(line)) {
22+
FLinearColor color(line.Tint);
23+
color *= Tint;
24+
const float lineLife = line.GetLineLife(GetWorld());
25+
if (FadeDuration > 0 && EraseTime > 0 && lineLife > (EraseTime - FadeDuration)) {
26+
const float fadeOpacity = (EraseTime - lineLife) / FadeDuration;
27+
color.A *= FMath::Clamp(fadeOpacity, 0.f, 1.f);
28+
}
29+
UWidgetBlueprintLibrary::DrawSpline(context, line.StartingPoint, line.StartingDirection, line.StoppingPoint, line.StoppingDirection, color, line.Size);
30+
}
31+
}
32+
}
33+
34+
void UReplicatedCanvasWidgetBase::CleanupLines(){
35+
if (EraseTime <= 0) {
36+
return;
37+
}
38+
while (LineData.Num() > 0 && LineData[0].GetLineLife(GetWorld()) > EraseTime) {
39+
LineData.RemoveAt(0);
40+
}
41+
}
42+
43+
// UReplicatedCanvasWidgetBase::UReplicatedCanvasWidgetBase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {
44+
//
45+
// }
46+
47+
void UReplicatedCanvasWidgetBase::TrySetupReplicator() {
48+
if (Replicator) { return; }
49+
50+
if (const auto subsys = GetWorld()->GetSubsystem<UWorldCanvasSubsystem>()) {
51+
52+
Replicator = subsys->Replicator;
53+
if (Replicator) {
54+
Replicator->OnLineAdded.AddDynamic(this, &UReplicatedCanvasWidgetBase::OnLineAddedToBoard);
55+
}
56+
}
57+
}
58+
59+
void UReplicatedCanvasWidgetBase::NativeConstruct() {
60+
Super::NativeConstruct();
61+
62+
if (!WidgetTree) { return; }
63+
64+
UOverlay* root = WidgetTree->ConstructWidget<UOverlay>(UOverlay::StaticClass(), TEXT("OverlayRoot"));
65+
WidgetTree->RootWidget = root;
66+
67+
DrawingPad = WidgetTree->ConstructWidget<UBorder>(UBorder::StaticClass(), TEXT("DrawingPad"));
68+
DrawingPad->SetVisibility(ESlateVisibility::Visible);
69+
DrawingPad->SetBrushColor(FLinearColor(0, 0, 0, 0));
70+
71+
if (UOverlaySlot* slot = root->AddChildToOverlay(DrawingPad)) {
72+
slot->SetHorizontalAlignment(HAlign_Fill);
73+
slot->SetHorizontalAlignment(HAlign_Fill);
74+
}
75+
76+
SetVisibility(ESlateVisibility::Visible);
77+
SetIsEnabled(true);
78+
SetIsFocusable(true);
79+
80+
}
81+
82+
void UReplicatedCanvasWidgetBase::NativeTick(const FGeometry& MyGeometry, float InDeltaTime) {
83+
Super::NativeTick(MyGeometry, InDeltaTime);
84+
TrySetupReplicator();
85+
CleanupLines();
86+
}
87+
88+
int32 UReplicatedCanvasWidgetBase::NativePaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
89+
const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const {
90+
91+
FPaintContext context(AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
92+
DrawLines(context);
93+
if (ShouldDraw()) {
94+
95+
}
96+
return Super::NativePaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
97+
}
98+
99+
#pragma region Mouse Overrides
100+
FReply UReplicatedCanvasWidgetBase::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) {
101+
if (InMouseEvent.GetEffectingButton() == FKey("LeftMouseButton")) {
102+
bWantsToDraw = true;
103+
104+
}
105+
106+
return Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
107+
}
108+
109+
FReply UReplicatedCanvasWidgetBase::NativeOnMouseMove(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) {
110+
if (ShouldDraw()) {
111+
112+
FVector2D currentPosition = InGeometry.AbsoluteToLocal( InMouseEvent.GetScreenSpacePosition());
113+
FVector2D currentDirection = FVector2D::ZeroVector;
114+
if (InMouseEvent.IsPointerEvent()) {
115+
currentDirection = InMouseEvent.GetCursorDelta();
116+
}
117+
if (InMouseEvent.IsTouchEvent()) {
118+
currentDirection = InMouseEvent.GetGestureDelta();
119+
}
120+
if (bStartedDrawing) {
121+
const FCanvasLineData line(GetDrawerName(), UGameplayStatics::GetTimeSeconds(GetWorld()), LastPosition, LastDirection, currentPosition, currentDirection, PenData.Size, PenData.Tint);
122+
LineData.Add(line);
123+
AddLineToState(line);
124+
}
125+
else {
126+
bStartedDrawing = true;
127+
}
128+
LastPosition = currentPosition;
129+
LastDirection = currentDirection;
130+
}
131+
return Super::NativeOnMouseMove(InGeometry, InMouseEvent);
132+
}
133+
134+
FReply UReplicatedCanvasWidgetBase::NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) {
135+
bWantsToDraw = false;
136+
bStartedDrawing = false;
137+
return Super::NativeOnMouseButtonUp(InGeometry, InMouseEvent);
138+
}
139+
140+
void UReplicatedCanvasWidgetBase::NativeOnMouseLeave(const FPointerEvent& InMouseEvent) {
141+
Super::NativeOnMouseLeave(InMouseEvent);
142+
bWantsToDraw = false;
143+
bStartedDrawing = false;
144+
}
145+
#pragma endregion Mouse Overrides
146+
147+
void UReplicatedCanvasWidgetBase::OnLineAddedToBoard(FName board, const FCanvasLineData& line) {
148+
UKismetSystemLibrary::PrintString(this, "Func Hit");
149+
150+
if (board != BoardName) {
151+
return;
152+
}
153+
if (true){//line.DrawingPlayer != GetDrawerName()) {
154+
LineData.Add(line);
155+
UKismetSystemLibrary::PrintString(this, "Line Added");
156+
}
157+
}
158+
159+
void UReplicatedCanvasWidgetBase::RefreshFromReplicator() {
160+
LineData.Empty();
161+
if (Replicator) {
162+
LineData = Replicator->GetCanvasLines(BoardName);
163+
}
164+
}
165+
166+
void UReplicatedCanvasWidgetBase::CleanBoard() {
167+
LineData.Empty();
168+
if (Replicator) {
169+
Replicator->CleanBoard(BoardName);
170+
}
171+
}
172+
173+
void UReplicatedCanvasWidgetBase::AddLineToState(const FCanvasLineData& line) {
174+
if (!StateHelper) {
175+
if (APlayerState* state = GetOwningPlayerState()) {
176+
StateHelper = Cast<UCanvasPlayerStateHelper>(state->GetComponentByClass(UCanvasPlayerStateHelper::StaticClass()));
177+
}
178+
}
179+
180+
if (StateHelper) {
181+
182+
StateHelper->AddLine(BoardName, line);
183+
}
184+
}
185+
186+
FName UReplicatedCanvasWidgetBase::GetDrawerName_Implementation() {
187+
if (DrawerName == FName()) {
188+
DrawerName = FName(GetOwningPlayerState(true)->GetPlayerName());
189+
}
190+
return DrawerName;
191+
}
192+
193+
bool UReplicatedCanvasWidgetBase::ShouldDraw_Implementation() const {
194+
195+
if (!bWantsToDraw || !(PenData.Size > 0) || !(PenData.Tint.A > 0)) {
196+
return false;
197+
}
198+
199+
return true;
200+
}

0 commit comments

Comments
 (0)