6684: Make server settings editor height adjustable by dragging r=heinrich5991 a=Robyt3

Same as for the envelope editor. Extract `RenderExtraEditorDragBar` function to reduce duplicate code.

Fix height being changed by repeated clicking on the draggable element by also resetting `s_Operation` when `Clicked` is `true`.

## Checklist

- [X] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


6685: Support dragging demo player controls to move them, fix minor related issues r=heinrich5991 a=Robyt3

Allow dragging the demo player controls anywhere on the screen. The controls can't be moved outside of the screen. Round corners are automatically disabled when the controls are on the edge of the screen.

https://github.com/ddnet/ddnet/assets/23437060/72510c1f-4fd2-426b-a631-3a78db5f7b8b

## Checklist

- [X] Tested the change ingame
- [X] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


6699: Add dragger prediction r=def- a=trml

..for servers with the new ddnetlaser. Tested this locally and on Fun server, and seems to work.

Also adjusted the criteria for when to send the original dragger id slightly, to improve prediction in some edge cases when going through solo/unsolo while being dragged.

## Checklist

- [x] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
Co-authored-by: trml <trml@users.noreply.github.com>
This commit is contained in:
bors[bot] 2023-06-03 20:46:26 +00:00 committed by GitHub
commit c227ed4bc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 378 additions and 94 deletions

View file

@ -2260,6 +2260,8 @@ if(CLIENT)
pickup_data.h
prediction/entities/character.cpp
prediction/entities/character.h
prediction/entities/dragger.cpp
prediction/entities/dragger.h
prediction/entities/laser.cpp
prediction/entities/laser.h
prediction/entities/pickup.cpp

View file

@ -2220,14 +2220,8 @@ bool CMenus::OnCursorMove(float x, float y, IInput::ECursorType CursorType)
bool CMenus::OnInput(const IInput::CEvent &Event)
{
// special handle esc and enter for popup purposes
if(Event.m_Flags & IInput::FLAG_PRESS && Event.m_Key == KEY_ESCAPE)
{
SetActive(!IsActive());
UI()->OnInput(Event);
return true;
}
if(IsActive())
// Escape key is always handled to activate/deactivate menu
if((Event.m_Flags & IInput::FLAG_PRESS && Event.m_Key == KEY_ESCAPE) || IsActive())
{
UI()->OnInput(Event);
return true;
@ -2308,6 +2302,8 @@ void CMenus::OnRender()
if(!IsActive())
{
if(UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE))
SetActive(true);
UI()->FinishCheck();
UI()->ClearHotkeys();
return;
@ -2359,6 +2355,9 @@ void CMenus::OnRender()
TextRender()->TextEx(&Cursor, aBuf, -1);
}
if(UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE))
SetActive(false);
UI()->FinishCheck();
UI()->ClearHotkeys();
}

View file

@ -437,6 +437,7 @@ protected:
void UpdateMusicState();
// found in menus_demo.cpp
vec2 m_DemoControlsPositionOffset = vec2(0.0f, 0.0f);
static bool DemoFilterChat(const void *pData, int Size, void *pUser);
bool FetchHeader(CDemoItem &Item);
void FetchAllHeaders();

View file

@ -223,7 +223,20 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
MainView.HSplitBottom(TotalHeight, nullptr, &DemoControls);
DemoControls.VSplitLeft(50.0f, nullptr, &DemoControls);
DemoControls.VSplitLeft(600.0f, &DemoControls, nullptr);
DemoControls.Draw(ms_ColorTabbarActive, IGraphics::CORNER_T, 10.0f);
const CUIRect DemoControlsOriginal = DemoControls;
DemoControls.x += m_DemoControlsPositionOffset.x;
DemoControls.y += m_DemoControlsPositionOffset.y;
int Corners = IGraphics::CORNER_NONE;
if(DemoControls.x > 0.0f && DemoControls.y > 0.0f)
Corners |= IGraphics::CORNER_TL;
if(DemoControls.x < MainView.w - DemoControls.w && DemoControls.y > 0.0f)
Corners |= IGraphics::CORNER_TR;
if(DemoControls.x > 0.0f && DemoControls.y < MainView.h - DemoControls.h)
Corners |= IGraphics::CORNER_BL;
if(DemoControls.x < MainView.w - DemoControls.w && DemoControls.y < MainView.h - DemoControls.h)
Corners |= IGraphics::CORNER_BR;
DemoControls.Draw(ms_ColorTabbarActive, Corners, 10.0f);
const CUIRect DemoControlsDragRect = DemoControls;
CUIRect SeekBar, ButtonBar, NameBar, SpeedBar;
DemoControls.Margin(5.0f, &DemoControls);
@ -232,6 +245,45 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
ButtonBar.HSplitBottom(NameBarHeight, &ButtonBar, &NameBar);
NameBar.HSplitTop(4.0f, nullptr, &NameBar);
// handle draggable demo controls
{
enum EDragOperation
{
OP_NONE,
OP_DRAGGING,
OP_CLICKED
};
static EDragOperation s_Operation = OP_NONE;
static vec2 s_InitialMouse = vec2(0.0f, 0.0f);
bool Clicked;
bool Abrupted;
if(int Result = UI()->DoDraggableButtonLogic(&s_Operation, 8, &DemoControlsDragRect, &Clicked, &Abrupted))
{
if(s_Operation == OP_NONE && Result == 1)
{
s_InitialMouse = UI()->MousePos();
s_Operation = OP_CLICKED;
}
if(Clicked || Abrupted)
s_Operation = OP_NONE;
if(s_Operation == OP_CLICKED && length(UI()->MousePos() - s_InitialMouse) > 5.0f)
{
s_Operation = OP_DRAGGING;
s_InitialMouse -= m_DemoControlsPositionOffset;
}
if(s_Operation == OP_DRAGGING)
{
m_DemoControlsPositionOffset = UI()->MousePos() - s_InitialMouse;
m_DemoControlsPositionOffset.x = clamp(m_DemoControlsPositionOffset.x, -DemoControlsOriginal.x, MainView.w - DemoControlsDragRect.w - DemoControlsOriginal.x);
m_DemoControlsPositionOffset.y = clamp(m_DemoControlsPositionOffset.y, -DemoControlsOriginal.y, MainView.h - DemoControlsDragRect.h - DemoControlsOriginal.y);
}
}
}
// do seekbar
{
const float Rounding = 5.0f;

View file

@ -30,6 +30,7 @@ void CTooltips::DoToolTip(const void *pID, const CUIRect *pNearRect, const char
{
uintptr_t ID = reinterpret_cast<uintptr_t>(pID);
const auto result = m_Tooltips.emplace(ID, CTooltip{
pID,
*pNearRect,
pText,
WidthHint,
@ -44,7 +45,7 @@ void CTooltips::DoToolTip(const void *pID, const CUIRect *pNearRect, const char
Tooltip.m_OnScreen = true;
if(UI()->MouseInside(&Tooltip.m_Rect))
if(UI()->HotItem() == Tooltip.m_pID)
{
SetActiveTooltip(Tooltip);
}
@ -56,7 +57,7 @@ void CTooltips::OnRender()
{
CTooltip &Tooltip = m_ActiveTooltip.value();
if(!UI()->MouseInside(&Tooltip.m_Rect))
if(UI()->HotItem() != Tooltip.m_pID)
{
Tooltip.m_OnScreen = false;
ClearActiveTooltip();

View file

@ -11,6 +11,7 @@
struct CTooltip
{
const void *m_pID;
CUIRect m_Rect;
const char *m_pText;
float m_WidthHint;

View file

@ -0,0 +1,161 @@
/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
#include "dragger.h"
#include "character.h"
#include <engine/shared/config.h>
#include <game/client/laser_data.h>
#include <game/collision.h>
#include <game/generated/protocol.h>
#include <game/mapitems.h>
void CDragger::Tick()
{
if(GameWorld()->GameTick() % (int)(GameWorld()->GameTickSpeed() * 0.15f) == 0)
{
int Flags;
int index = Collision()->IsMover(m_Pos.x, m_Pos.y, &Flags);
if(index)
{
m_Core = Collision()->CpSpeed(index, Flags);
}
m_Pos += m_Core;
LookForPlayersToDrag();
}
DraggerBeamTick();
}
void CDragger::LookForPlayersToDrag()
{
// Create a list of players who are in the range of the dragger
CEntity *apPlayersInRange[MAX_CLIENTS];
mem_zero(apPlayersInRange, sizeof(apPlayersInRange));
int NumPlayersInRange = GameWorld()->FindEntities(m_Pos,
g_Config.m_SvDraggerRange - CCharacterCore::PhysicalSize(),
apPlayersInRange, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
// The closest player (within range) in a team is selected as the target
int ClosestTargetId = -1;
bool CanStillBeTeamTarget = false;
int MinDistInTeam = 0;
for(int i = 0; i < NumPlayersInRange; i++)
{
CCharacter *pTarget = static_cast<CCharacter *>(apPlayersInRange[i]);
const int &TargetTeam = pTarget->Team();
// Do not create a dragger beam for super player
if(TargetTeam == TEAM_SUPER)
{
continue;
}
// If the dragger is disabled for the target's team, no dragger beam will be generated
if(m_Layer == LAYER_SWITCH && m_Number > 0 &&
!Switchers()[m_Number].m_aStatus[TargetTeam])
{
continue;
}
// Dragger beams can be created only for reachable, alive players
int IsReachable =
m_IgnoreWalls ?
!Collision()->IntersectNoLaserNW(m_Pos, pTarget->m_Pos, 0, 0) :
!Collision()->IntersectNoLaser(m_Pos, pTarget->m_Pos, 0, 0);
if(IsReachable)
{
const int &TargetClientId = pTarget->GetCID();
int Distance = distance(pTarget->m_Pos, m_Pos);
if(MinDistInTeam == 0 || MinDistInTeam > Distance)
{
MinDistInTeam = Distance;
ClosestTargetId = TargetClientId;
}
if(TargetClientId == m_TargetId)
{
CanStillBeTeamTarget = true;
}
}
}
// Set the closest player for each team as a target if the team does not have a target player yet
if((m_TargetId != -1 && !CanStillBeTeamTarget) || m_TargetId == -1)
{
m_TargetId = ClosestTargetId;
}
}
void CDragger::DraggerBeamReset()
{
m_TargetId = -1;
}
void CDragger::DraggerBeamTick()
{
CCharacter *pTarget = GameWorld()->GetCharacterByID(m_TargetId);
if(!pTarget)
{
DraggerBeamReset();
return;
}
if(GameWorld()->GameTick() % (int)(GameWorld()->GameTickSpeed() * 0.15f) == 0)
{
if(m_Layer == LAYER_SWITCH && m_Number > 0 &&
!Switchers()[m_Number].m_aStatus[pTarget->Team()])
{
DraggerBeamReset();
return;
}
}
// When the dragger can no longer reach the target player, the dragger beam dissolves
int IsReachable =
m_IgnoreWalls ?
!Collision()->IntersectNoLaserNW(m_Pos, pTarget->m_Pos, 0, 0) :
!Collision()->IntersectNoLaser(m_Pos, pTarget->m_Pos, 0, 0);
if(!IsReachable || distance(pTarget->m_Pos, m_Pos) >= g_Config.m_SvDraggerRange)
{
DraggerBeamReset();
return;
}
// In the center of the dragger a tee does not experience speed-up
else if(distance(pTarget->m_Pos, m_Pos) > 28)
{
vec2 Temp = pTarget->Core()->m_Vel + (normalize(m_Pos - pTarget->m_Pos) * m_Strength);
pTarget->Core()->m_Vel = ClampVel(pTarget->m_MoveRestrictions, Temp);
}
}
CDragger::CDragger(CGameWorld *pGameWorld, int ID, const CLaserData *pData) :
CEntity(pGameWorld, CGameWorld::ENTTYPE_DRAGGER)
{
m_Core = vec2(0.f, 0.f);
m_ID = ID;
m_TargetId = -1;
m_Strength = 0;
m_IgnoreWalls = false;
if(0 <= pData->m_Subtype && pData->m_Subtype < NUM_LASERDRAGGERTYPES)
{
m_IgnoreWalls = (pData->m_Subtype & 1);
m_Strength = (pData->m_Subtype >> 1) + 1;
}
m_Number = pData->m_SwitchNumber;
m_Layer = m_Number > 0 ? LAYER_SWITCH : LAYER_GAME;
Read(pData);
}
void CDragger::Read(const CLaserData *pData)
{
m_Pos = pData->m_From;
m_TargetId = pData->m_Owner;
}
bool CDragger::Match(CDragger *pDragger)
{
return pDragger->m_Strength == m_Strength && pDragger->m_Number == m_Number && pDragger->m_IgnoreWalls == m_IgnoreWalls;
}

View file

@ -0,0 +1,29 @@
/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
#ifndef GAME_CLIENT_PREDICTION_ENTITIES_DRAGGER_H
#define GAME_CLIENT_PREDICTION_ENTITIES_DRAGGER_H
#include <game/client/prediction/entity.h>
class CLaserData;
class CDragger : public CEntity
{
vec2 m_Core;
float m_Strength;
bool m_IgnoreWalls;
int m_TargetId;
void LookForPlayersToDrag();
void DraggerBeamTick();
void DraggerBeamReset();
public:
CDragger(CGameWorld *pGameWorld, int ID, const CLaserData *pData);
bool Match(CDragger *pDragger);
void Read(const CLaserData *pData);
float GetStrength() { return m_Strength; }
void Tick() override;
};
#endif // GAME_CLIENT_PREDICTION_ENTITIES_DRAGGER_H

View file

@ -3,6 +3,7 @@
#include "gameworld.h"
#include "entities/character.h"
#include "entities/dragger.h"
#include "entities/laser.h"
#include "entities/pickup.h"
#include "entities/projectile.h"
@ -497,37 +498,54 @@ void CGameWorld::NetObjAdd(int ObjID, int ObjType, const void *pObjData, const C
else if((ObjType == NETOBJTYPE_LASER || ObjType == NETOBJTYPE_DDNETLASER) && m_WorldConfig.m_PredictWeapons)
{
CLaserData Data = ExtractLaserInfo(ObjType, pObjData, this, pDataEx);
if((Data.m_Type >= 0 && Data.m_Type != LASERTYPE_RIFLE && Data.m_Type != LASERTYPE_SHOTGUN) || !IsLocalTeam(Data.m_Owner))
{
if(!IsLocalTeam(Data.m_Owner))
return;
}
CLaser NetLaser = CLaser(this, ObjID, &Data);
CLaser *pMatching = 0;
if(CLaser *pLaser = dynamic_cast<CLaser *>(GetEntity(ObjID, ENTTYPE_LASER)))
if(NetLaser.Match(pLaser))
pMatching = pLaser;
if(!pMatching)
if(Data.m_Type == LASERTYPE_RIFLE || Data.m_Type == LASERTYPE_SHOTGUN || Data.m_Type < 0)
{
for(CEntity *pEnt = FindFirst(CGameWorld::ENTTYPE_LASER); pEnt; pEnt = pEnt->TypeNext())
{
auto *const pLaser = dynamic_cast<CLaser *>(pEnt);
if(pLaser && pLaser->m_ID == -1 && NetLaser.Match(pLaser))
{
CLaser NetLaser = CLaser(this, ObjID, &Data);
CLaser *pMatching = 0;
if(CLaser *pLaser = dynamic_cast<CLaser *>(GetEntity(ObjID, ENTTYPE_LASER)))
if(NetLaser.Match(pLaser))
pMatching = pLaser;
pMatching->m_ID = ObjID;
break;
if(!pMatching)
{
for(CEntity *pEnt = FindFirst(CGameWorld::ENTTYPE_LASER); pEnt; pEnt = pEnt->TypeNext())
{
auto *const pLaser = dynamic_cast<CLaser *>(pEnt);
if(pLaser && pLaser->m_ID == -1 && NetLaser.Match(pLaser))
{
pMatching = pLaser;
pMatching->m_ID = ObjID;
break;
}
}
}
if(pMatching)
{
pMatching->Keep();
if(distance(NetLaser.m_From, NetLaser.m_Pos) < distance(pMatching->m_From, pMatching->m_Pos) - 2.f)
{
// if the laser stopped earlier than predicted, set the energy to 0
pMatching->m_Energy = 0.f;
pMatching->m_Pos = NetLaser.m_Pos;
}
}
}
if(pMatching)
else if(Data.m_Type == LASERTYPE_DRAGGER)
{
pMatching->Keep();
if(distance(NetLaser.m_From, NetLaser.m_Pos) < distance(pMatching->m_From, pMatching->m_Pos) - 2.f)
CDragger NetDragger = CDragger(this, ObjID, &Data);
if(NetDragger.GetStrength() > 0)
{
// if the laser stopped earlier than predicted, set the energy to 0
pMatching->m_Energy = 0.f;
pMatching->m_Pos = NetLaser.m_Pos;
auto *pDragger = dynamic_cast<CDragger *>(GetEntity(ObjID, ENTTYPE_DRAGGER));
if(pDragger && NetDragger.Match(pDragger))
{
pDragger->Keep();
pDragger->Read(&Data);
return;
}
CEntity *pEnt = new CDragger(NetDragger);
InsertEntity(pEnt);
}
}
}
@ -606,6 +624,8 @@ void CGameWorld::CopyWorld(CGameWorld *pFrom)
pCopy = new CProjectile(*((CProjectile *)pEnt));
else if(Type == ENTTYPE_LASER)
pCopy = new CLaser(*((CLaser *)pEnt));
else if(Type == ENTTYPE_DRAGGER)
pCopy = new CDragger(*((CDragger *)pEnt));
else if(Type == ENTTYPE_CHARACTER)
pCopy = new CCharacter(*((CCharacter *)pEnt));
else if(Type == ENTTYPE_PICKUP)
@ -650,10 +670,21 @@ CEntity *CGameWorld::FindMatch(int ObjID, int ObjType, const void *pObjData)
case NETOBJTYPE_DDNETLASER:
{
CLaserData Data = ExtractLaserInfo(ObjType, pObjData, this, nullptr);
CLaser *pEnt = (CLaser *)GetEntity(ObjID, ENTTYPE_LASER);
if(pEnt && CLaser(this, ObjID, &Data).Match(pEnt))
if(Data.m_Type == LASERTYPE_RIFLE || Data.m_Type == LASERTYPE_SHOTGUN)
{
return pEnt;
CLaser *pEnt = (CLaser *)GetEntity(ObjID, ENTTYPE_LASER);
if(pEnt && CLaser(this, ObjID, &Data).Match(pEnt))
{
return pEnt;
}
}
else if(Data.m_Type == LASERTYPE_DRAGGER)
{
CDragger *pEnt = (CDragger *)GetEntity(ObjID, ENTTYPE_DRAGGER);
if(pEnt && CDragger(this, ObjID, &Data).Match(pEnt))
{
return pEnt;
}
}
return 0;
}

View file

@ -21,6 +21,11 @@ public:
{
ENTTYPE_PROJECTILE = 0,
ENTTYPE_LASER,
ENTTYPE_DOOR,
ENTTYPE_DRAGGER,
ENTTYPE_LIGHT,
ENTTYPE_GUN,
ENTTYPE_PLASMA,
ENTTYPE_PICKUP,
ENTTYPE_FLAG,
ENTTYPE_CHARACTER,

View file

@ -5226,6 +5226,8 @@ void CEditor::RemoveUnusedEnvelopes()
void CEditor::RenderEnvelopeEditor(CUIRect View)
{
RenderExtraEditorDragBar(View, &m_EnvelopeEditorSplit);
if(m_SelectedEnvelope < 0)
m_SelectedEnvelope = 0;
if(m_SelectedEnvelope >= (int)m_Map.m_vpEnvelopes.size())
@ -5235,12 +5237,6 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
if(m_SelectedEnvelope >= 0 && m_SelectedEnvelope < (int)m_Map.m_vpEnvelopes.size())
pEnvelope = m_Map.m_vpEnvelopes[m_SelectedEnvelope];
CUIRect DragBar = {
View.x,
View.y - 2.0f, // use margin
View.w,
22.0f,
};
CUIRect ToolBar, CurveBar, ColorBar;
View.HSplitTop(15.0f, &ToolBar, &View);
View.HSplitTop(15.0f, &CurveBar, &View);
@ -5249,47 +5245,6 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
bool CurrentEnvelopeSwitched = false;
// do the dragbar
{
enum
{
OP_NONE,
OP_DRAG_HEADER,
OP_CLICK_HEADER
};
static int s_Operation = 0;
static float s_InitialMouseY = 0.0f;
static float s_InitialMouseOffsetY = 0.0f;
static int s_DragBar = 0;
bool Clicked;
bool Abrupted;
if(int Result = DoButton_DraggableEx(&s_DragBar, "", 8, &DragBar, &Clicked, &Abrupted, 0, "Change the size of the editor by dragging."))
{
if(s_Operation == OP_NONE && Result == 1)
{
s_InitialMouseY = UI()->MouseY();
s_InitialMouseOffsetY = UI()->MouseY() - DragBar.y;
s_Operation = OP_CLICK_HEADER;
}
if(Abrupted)
s_Operation = OP_NONE;
if(s_Operation == OP_CLICK_HEADER && absolute(UI()->MouseY() - s_InitialMouseY) > 5)
s_Operation = OP_DRAG_HEADER;
if(s_Operation == OP_DRAG_HEADER)
{
if(Clicked)
s_Operation = OP_NONE;
m_EnvelopeEditorSplit = s_InitialMouseOffsetY + View.y + View.h - UI()->MouseY();
m_EnvelopeEditorSplit = clamp(m_EnvelopeEditorSplit, 100.0f, 400.0f);
}
}
}
// do the toolbar
{
CUIRect Button;
@ -5818,6 +5773,8 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
void CEditor::RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEditorLast)
{
RenderExtraEditorDragBar(View, &m_ServerSettingsEditorSplit);
static int s_CommandSelectedIndex = -1;
CUIRect ToolBar;
@ -5963,6 +5920,47 @@ void CEditor::RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEd
s_ScrollRegion.End();
}
void CEditor::RenderExtraEditorDragBar(CUIRect View, float *pSplit)
{
const CUIRect DragBar = {
View.x,
View.y - 2.0f, // use margin
View.w,
22.0f,
};
enum EDragOperation
{
OP_NONE,
OP_DRAGGING,
OP_CLICKED
};
static EDragOperation s_Operation = OP_NONE;
static float s_InitialMouseY = 0.0f;
static float s_InitialMouseOffsetY = 0.0f;
bool Clicked;
bool Abrupted;
if(int Result = DoButton_DraggableEx(&s_Operation, "", 8, &DragBar, &Clicked, &Abrupted, 0, "Change the size of the editor by dragging."))
{
if(s_Operation == OP_NONE && Result == 1)
{
s_InitialMouseY = UI()->MouseY();
s_InitialMouseOffsetY = UI()->MouseY() - DragBar.y;
s_Operation = OP_CLICKED;
}
if(Clicked || Abrupted)
s_Operation = OP_NONE;
if(s_Operation == OP_CLICKED && absolute(UI()->MouseY() - s_InitialMouseY) > 5.0f)
s_Operation = OP_DRAGGING;
if(s_Operation == OP_DRAGGING)
*pSplit = clamp(s_InitialMouseOffsetY + View.y + View.h - UI()->MouseY(), 100.0f, 400.0f);
}
}
void CEditor::RenderMenubar(CUIRect MenuBar)
{
CUIRect FileButton;
@ -6049,7 +6047,7 @@ void CEditor::Render()
View.HSplitBottom(m_EnvelopeEditorSplit, &View, &ExtraEditor);
if(m_ShowServerSettingsEditor && !m_ShowPicker)
View.HSplitBottom(250.0f, &View, &ExtraEditor);
View.HSplitBottom(m_ServerSettingsEditorSplit, &View, &ExtraEditor);
}
else
{

View file

@ -810,6 +810,7 @@ public:
m_ShowEnvelopeEditor = false;
m_EnvelopeEditorSplit = 250.0f;
m_ShowServerSettingsEditor = false;
m_ServerSettingsEditorSplit = 250.0f;
m_ShowEnvelopePreview = SHOWENV_NONE;
m_SelectedQuadEnvelope = -1;
@ -1073,6 +1074,8 @@ public:
bool m_ShowEnvelopeEditor;
float m_EnvelopeEditorSplit;
bool m_ShowServerSettingsEditor;
float m_ServerSettingsEditorSplit;
enum EShowEnvelope
{
@ -1081,7 +1084,6 @@ public:
SHOWENV_ALL
};
EShowEnvelope m_ShowEnvelopePreview;
bool m_ShowServerSettingsEditor;
bool m_ShowPicker;
std::vector<int> m_vSelectedLayers;
@ -1234,8 +1236,10 @@ public:
void RenderSounds(CUIRect Toolbox);
void RenderModebar(CUIRect View);
void RenderStatusbar(CUIRect View);
void RenderEnvelopeEditor(CUIRect View);
void RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEditorLast);
void RenderExtraEditorDragBar(CUIRect View, float *pSplit);
void RenderMenubar(CUIRect Menubar);
void RenderFileDialog();

View file

@ -168,17 +168,17 @@ bool CDragger::WillDraggerBeamUseDraggerID(int TargetClientID, int SnappingClien
CCharacter *pSnapChar = GameServer()->GetPlayerChar(SnappingClientID);
if(pTargetChar && pSnapChar && m_apDraggerBeam[TargetClientID] != nullptr)
{
if(pSnapChar->Teams()->m_Core.GetSolo(SnappingClientID))
const int SnapTeam = pSnapChar->Team();
const int TargetTeam = pTargetChar->Team();
if(SnapTeam == TargetTeam && SnapTeam < MAX_CLIENTS)
{
return TargetClientID == SnappingClientID;
}
else if(!pTargetChar->Teams()->m_Core.GetSolo(TargetClientID))
{
const int SnapTeam = pSnapChar->Team();
const int TargetTeam = pTargetChar->Team();
if(SnapTeam == TargetTeam && SnapTeam < MAX_CLIENTS && m_aTargetIdInTeam[SnapTeam] == TargetClientID)
if(pSnapChar->Teams()->m_Core.GetSolo(SnappingClientID) || m_aTargetIdInTeam[SnapTeam] < 0)
{
return true;
return SnappingClientID == TargetClientID;
}
else
{
return m_aTargetIdInTeam[SnapTeam] == TargetClientID;
}
}
}