mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-19 12:35:52 -04:00
Port InputHandler and PickingHandler to C
This commit is contained in:
parent
d05f4ab214
commit
6430656cfe
@ -68,7 +68,7 @@ namespace ClassicalSharp {
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CheckIsFree(Game game, BlockID block) {
|
||||
static bool CheckIsFree(Game game, BlockID block) {
|
||||
Vector3 pos = (Vector3)game.SelectedPos.TranslatedPos;
|
||||
LocalPlayer p = game.LocalPlayer;
|
||||
|
||||
@ -99,21 +99,20 @@ namespace ClassicalSharp {
|
||||
static bool PushbackPlace(Game game, AABB blockBB) {
|
||||
LocalPlayer p = game.LocalPlayer;
|
||||
Vector3 curPos = p.Position, adjPos = p.Position;
|
||||
|
||||
|
||||
// Offset position by the closest face
|
||||
PickedPos selected = game.SelectedPos;
|
||||
if (selected.Face == BlockFace.XMax) {
|
||||
BlockFace closestFace = game.SelectedPos.Face;
|
||||
if (closestFace == BlockFace.XMax) {
|
||||
adjPos.X = blockBB.Max.X + 0.5f;
|
||||
} else if (selected.Face == BlockFace.ZMax) {
|
||||
} else if (closestFace == BlockFace.ZMax) {
|
||||
adjPos.Z = blockBB.Max.Z + 0.5f;
|
||||
} else if (selected.Face == BlockFace.XMin) {
|
||||
} else if (closestFace == BlockFace.XMin) {
|
||||
adjPos.X = blockBB.Min.X - 0.5f;
|
||||
} else if (selected.Face == BlockFace.ZMin) {
|
||||
} else if (closestFace == BlockFace.ZMin) {
|
||||
adjPos.Z = blockBB.Min.Z - 0.5f;
|
||||
} else if (selected.Face == BlockFace.YMax) {
|
||||
} else if (closestFace == BlockFace.YMax) {
|
||||
adjPos.Y = blockBB.Min.Y + 1 + Entity.Adjustment;
|
||||
} else if (selected.Face == BlockFace.YMin) {
|
||||
} else if (closestFace == BlockFace.YMin) {
|
||||
adjPos.Y = blockBB.Min.Y - p.Size.Y - Entity.Adjustment;
|
||||
}
|
||||
|
||||
|
@ -207,6 +207,7 @@
|
||||
<ClInclude Include="Hotkeys.h" />
|
||||
<ClInclude Include="IModel.h" />
|
||||
<ClInclude Include="Input.h" />
|
||||
<ClInclude Include="InputHandler.h" />
|
||||
<ClInclude Include="Intersection.h" />
|
||||
<ClInclude Include="Inventory.h" />
|
||||
<ClInclude Include="IsometricDrawer.h" />
|
||||
@ -280,6 +281,7 @@
|
||||
<ClCompile Include="Gui.c" />
|
||||
<ClCompile Include="HeldBlockRenderer.c" />
|
||||
<ClCompile Include="Hotkeys.c" />
|
||||
<ClCompile Include="InputHandler.c" />
|
||||
<ClCompile Include="Inventory.c" />
|
||||
<ClCompile Include="MapGenerator.c" />
|
||||
<ClCompile Include="FrustumCulling.c" />
|
||||
|
@ -381,6 +381,9 @@
|
||||
<ClInclude Include="HeldBlockRenderer.h">
|
||||
<Filter>Header Files\Rendering</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InputHandler.h">
|
||||
<Filter>Header Files\Game</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Noise.c">
|
||||
@ -599,5 +602,8 @@
|
||||
<ClCompile Include="HeldBlockRenderer.c">
|
||||
<Filter>Source Files\Rendering</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InputHandler.c">
|
||||
<Filter>Source Files\Game</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -39,7 +39,7 @@ bool Game_GetCursorVisible(void) { return Game_CursorVisible; }
|
||||
void Game_SetCursorVisible(bool visible) {
|
||||
/* Defer mouse visibility changes */
|
||||
Game_realCursorVisible = visible;
|
||||
if (Gui_OverlayCount > 0) return;
|
||||
if (Gui_OverlaysCount > 0) return;
|
||||
|
||||
/* Only set the value when it has changed */
|
||||
if (Game_CursorVisible == visible) return;
|
||||
|
@ -104,11 +104,11 @@ void Gui_Init(void) {
|
||||
}
|
||||
|
||||
void Gui_Reset(void) {
|
||||
UInt32 i;
|
||||
for (i = 0; i < Gui_OverlayCount; i++) {
|
||||
Int32 i;
|
||||
for (i = 0; i < Gui_OverlaysCount; i++) {
|
||||
Gui_Overlays[i]->Base.Free(&Gui_Overlays[i]->Base);
|
||||
}
|
||||
Gui_OverlayCount = 0;
|
||||
Gui_OverlaysCount = 0;
|
||||
}
|
||||
|
||||
void Gui_Free(void) {
|
||||
@ -134,7 +134,7 @@ IGameComponent Gui_MakeGameComponent(void) {
|
||||
}
|
||||
|
||||
Screen* Gui_GetActiveScreen(void) {
|
||||
return Gui_OverlayCount > 0 ? Gui_Overlays[0] : Gui_GetUnderlyingScreen();
|
||||
return Gui_OverlaysCount > 0 ? Gui_Overlays[0] : Gui_GetUnderlyingScreen();
|
||||
}
|
||||
|
||||
Screen* Gui_GetUnderlyingScreen(void) {
|
||||
@ -167,14 +167,14 @@ void Gui_RefreshHud(void) {
|
||||
}
|
||||
|
||||
void Gui_ShowOverlay(Screen* overlay) {
|
||||
if (Gui_OverlayCount == GUI_MAX_OVERLAYS) {
|
||||
if (Gui_OverlaysCount == GUI_MAX_OVERLAYS) {
|
||||
ErrorHandler_Fail("Cannot have more than 40 overlays");
|
||||
}
|
||||
bool visible = Game_GetCursorVisible();
|
||||
if (Gui_OverlayCount == 0) Game_SetCursorVisible(true);
|
||||
if (Gui_OverlaysCount == 0) Game_SetCursorVisible(true);
|
||||
|
||||
Gui_Overlays[Gui_OverlayCount++] = overlay;
|
||||
if (Gui_OverlayCount == 1) Game_SetCursorVisible(visible); /* Save cursor visibility state */
|
||||
Gui_Overlays[Gui_OverlaysCount++] = overlay;
|
||||
if (Gui_OverlaysCount == 1) Game_SetCursorVisible(visible); /* Save cursor visibility state */
|
||||
overlay->Base.Init(&overlay->Base);
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ void Gui_RenderGui(Real64 delta) {
|
||||
Gui_HUD->Base.Render(&Gui_HUD->Base, delta);
|
||||
}
|
||||
|
||||
if (Gui_OverlayCount > 0) {
|
||||
if (Gui_OverlaysCount > 0) {
|
||||
Gui_Overlays[0]->Base.Render(&Gui_Overlays[0]->Base, delta);
|
||||
}
|
||||
GfxCommon_Mode3D();
|
||||
@ -206,8 +206,8 @@ void Gui_OnResize(void) {
|
||||
}
|
||||
Gui_HUD->OnResize(&Gui_HUD->Base);
|
||||
|
||||
UInt32 i;
|
||||
for (i = 0; i < Gui_OverlayCount; i++) {
|
||||
Int32 i;
|
||||
for (i = 0; i < Gui_OverlaysCount; i++) {
|
||||
Gui_Overlays[i]->OnResize(&Gui_Overlays[i]->Base);
|
||||
}
|
||||
}
|
||||
|
@ -76,11 +76,10 @@ Screen* Gui_HUD;
|
||||
Screen* Gui_Active;
|
||||
#define GUI_MAX_OVERLAYS 40
|
||||
Screen* Gui_Overlays[GUI_MAX_OVERLAYS];
|
||||
UInt32 Gui_OverlayCount;
|
||||
Int32 Gui_OverlaysCount;
|
||||
|
||||
Int32 Gui_CalcPos(UInt8 anchor, Int32 offset, Int32 size, Int32 axisLen);
|
||||
bool Gui_Contains(Int32 recX, Int32 recY, Int32 width, Int32 height, Int32 x, Int32 y);
|
||||
/* Creates game component implementation. */
|
||||
IGameComponent Gui_MakeGameComponent(void);
|
||||
/* Gets the screen that the user is currently interacting with.
|
||||
This means if an overlay is active, it will be over the top of other screens. */
|
||||
|
429
src/Client/InputHandler.c
Normal file
429
src/Client/InputHandler.c
Normal file
@ -0,0 +1,429 @@
|
||||
#include "InputHandler.h"
|
||||
#include "Utils.h"
|
||||
#include "Hotkeys.h"
|
||||
#include "ServerConnection.h"
|
||||
#include "Game.h"
|
||||
#include "Platform.h"
|
||||
#include "ExtMath.h"
|
||||
#include "Camera.h"
|
||||
#include "Inventory.h"
|
||||
#include "World.h"
|
||||
#include "Event.h"
|
||||
#include "GameMode.h"
|
||||
#include "Window.h"
|
||||
#include "Player.h"
|
||||
#include "Chat.h"
|
||||
#include "Funcs.h"
|
||||
#include "Screens.h"
|
||||
|
||||
bool input_buttonsDown[3];
|
||||
Int32 input_pickingId = -1;
|
||||
Int32 input_normViewDists[] = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
|
||||
Int32 input_classicViewDists[] = { 8, 32, 128, 512 };
|
||||
Key input_lastKey;
|
||||
DateTime input_lastClick;
|
||||
Real32 input_fovIndex = -1.0f;
|
||||
|
||||
bool InputHandler_IsMousePressed(MouseButton button) {
|
||||
if (Mouse_IsPressed(button)) return true;
|
||||
|
||||
/* Key --> mouse mappings */
|
||||
if (button == MouseButton_Left && KeyBind_IsPressed(KeyBind_MouseLeft)) return true;
|
||||
if (button == MouseButton_Middle && KeyBind_IsPressed(KeyBind_MouseMiddle)) return true;
|
||||
if (button == MouseButton_Right && KeyBind_IsPressed(KeyBind_MouseRight)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void InputHandler_ButtonStateUpdate(MouseButton button, bool pressed) {
|
||||
/* defer getting the targeted entity as it's a costly operation */
|
||||
if (input_pickingId == -1) {
|
||||
Entity* p = &LocalPlayer_Instance.Base.Base;
|
||||
input_pickingId = Entities_GetCloset(p);
|
||||
}
|
||||
|
||||
EntityID id = (EntityID)input_pickingId;
|
||||
ServerConnection_SendPlayerClick(button, pressed, id, &Game_SelectedPos);
|
||||
input_buttonsDown[button] = pressed;
|
||||
}
|
||||
|
||||
void InputHandler_ButtonStateChanged(MouseButton button, bool pressed) {
|
||||
if (pressed) {
|
||||
/* Can send multiple Pressed events */
|
||||
InputHandler_ButtonStateUpdate(button, true);
|
||||
} else {
|
||||
if (!input_buttonsDown[button]) return;
|
||||
InputHandler_ButtonStateUpdate(button, false);
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler_ScreenChanged(Screen* oldScreen, Screen* newScreen) {
|
||||
if (oldScreen != NULL && oldScreen->HandlesAllInput) {
|
||||
input_lastClick = Platform_CurrentUTCTime();
|
||||
}
|
||||
|
||||
if (ServerConnection_SupportsPlayerClick) {
|
||||
input_pickingId = -1;
|
||||
InputHandler_ButtonStateChanged(MouseButton_Left, false);
|
||||
InputHandler_ButtonStateChanged(MouseButton_Right, false);
|
||||
InputHandler_ButtonStateChanged(MouseButton_Middle, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool InputHandler_IsShutdown(Key key, Key last) {
|
||||
if (key == Key_F4 && (last == Key_AltLeft || last == Key_AltRight)) return true;
|
||||
|
||||
/* On OSX, Cmd+Q should also terminate the process. */
|
||||
#if CC_BUILD_OSX
|
||||
return key == Key_Q && (last == Key_WinLeft || last == Key_WinRight);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputHandler_Toggle(Key key, bool* target, const UInt8* enableMsg, const UInt8* disableMsg) {
|
||||
*target = !(*target);
|
||||
UInt8 msgBuffer[String_BufferSize(STRING_SIZE * 2)];
|
||||
String msg = String_InitAndClearArray(msgBuffer);
|
||||
|
||||
String_AppendConst(&msg, (*target) ? enableMsg : disableMsg);
|
||||
String_AppendConst(&msg, ". &ePress &a");
|
||||
String_AppendConst(&msg, Key_Names[key]);
|
||||
String_AppendConst(&msg, (*target) ? " &eto disable." : " &eto re-enable.");
|
||||
Chat_Add(&msg);
|
||||
}
|
||||
|
||||
void InputHandler_CycleDistanceForwards(Int32* viewDists, Int32 count) {
|
||||
Int32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
Int32 dist = viewDists[i];
|
||||
if (dist > Game_UserViewDistance) {
|
||||
Game_SetViewDistance(dist, true); return;
|
||||
}
|
||||
}
|
||||
Game_SetViewDistance(viewDists[0], true);
|
||||
}
|
||||
|
||||
void InputHandler_CycleDistanceBackwards(Int32* viewDists, Int32 count) {
|
||||
Int32 i;
|
||||
for (i = count - 1; i >= 0; i--) {
|
||||
Int32 dist = viewDists[i];
|
||||
if (dist < Game_UserViewDistance) {
|
||||
Game_SetViewDistance(dist, true); return;
|
||||
}
|
||||
}
|
||||
Game_SetViewDistance(viewDists[count - 1], true);
|
||||
}
|
||||
|
||||
bool InputHandler_SetFOV(Int32 fov, bool setZoom) {
|
||||
if (Game_Fov == fov) return true;
|
||||
HacksComp* h = &LocalPlayer_Instance.Hacks;
|
||||
if (!h->Enabled || !h->CanAnyHacks || !h->CanUseThirdPersonCamera) return false;
|
||||
|
||||
Game_Fov = fov;
|
||||
if (setZoom) Game_ZoomFov = fov;
|
||||
Game_UpdateProjection();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputHandler_DoFovZoom(Real32 deltaPrecise) {
|
||||
if (!KeyBind_IsPressed(KeyBind_ZoomScrolling)) return false;
|
||||
HacksComp* h = &LocalPlayer_Instance.Hacks;
|
||||
if (!h->Enabled || !h->CanAnyHacks || !h->CanUseThirdPersonCamera) return false;
|
||||
|
||||
if (input_fovIndex == -1.0f) input_fovIndex = Game_ZoomFov;
|
||||
input_fovIndex -= deltaPrecise * 5.0f;
|
||||
|
||||
Math_Clamp(input_fovIndex, 1.0f, Game_DefaultFov);
|
||||
return InputHandler_SetFOV((Int32)input_fovIndex, true);
|
||||
}
|
||||
|
||||
bool InputHandler_HandleCoreKey(Key key) {
|
||||
if (key == KeyBind_Get(KeyBind_HideGui)) {
|
||||
Game_HideGui = !Game_HideGui;
|
||||
} else if (key == KeyBind_Get(KeyBind_HideFps)) {
|
||||
Game_ShowFPS = !Game_ShowFPS;
|
||||
} else if (key == KeyBind_Get(KeyBind_Fullscreen)) {
|
||||
UInt8 state = Window_GetWindowState();
|
||||
if (state != WINDOW_STATE_MAXIMISED) {
|
||||
bool fullscreen = state == WINDOW_STATE_FULLSCREEN;
|
||||
Window_SetWindowState(fullscreen ? WINDOW_STATE_NORMAL : WINDOW_STATE_FULLSCREEN);
|
||||
}
|
||||
} else if (key == KeyBind_Get(KeyBind_SmoothCamera)) {
|
||||
InputHandler_Toggle(key, &Game_SmoothCamera,
|
||||
" &eSmooth camera is &aenabled",
|
||||
" &eSmooth camera is &cdisabled");
|
||||
} else if (key == KeyBind_Get(KeyBind_AxisLines)) {
|
||||
InputHandler_Toggle(key, &Game_ShowAxisLines,
|
||||
" &eAxis lines (&4X&e, &2Y&e, &1Z&e) now show",
|
||||
" &eAxis lines no longer show");
|
||||
} else if (key == KeyBind_Get(KeyBind_Autorotate)) {
|
||||
InputHandler_Toggle(key, &Game_AutoRotate,
|
||||
" &eAuto rotate is &aenabled",
|
||||
" &eAuto rotate is &cdisabled");
|
||||
} else if (key == KeyBind_Get(KeyBind_ThirdPerson)) {
|
||||
Camera_CycleActive();
|
||||
} else if (key == KeyBind_Get(KeyBind_ToggleFog)) {
|
||||
Int32* viewDists = Game_UseClassicOptions ? input_classicViewDists : input_normViewDists;
|
||||
Int32 count = Game_UseClassicOptions ? Array_Elems(input_classicViewDists) : Array_Elems(input_normViewDists);
|
||||
|
||||
if (Key_IsShiftPressed()) {
|
||||
InputHandler_CycleDistanceBackwards(viewDists, count);
|
||||
} else {
|
||||
InputHandler_CycleDistanceForwards(viewDists, count);
|
||||
}
|
||||
} else if ((key == KeyBind_Get(KeyBind_PauseOrExit) || key == Key_Pause) && World_Blocks != NULL) {
|
||||
Screen* screen = PauseScreen_MakeInstance();
|
||||
Gui_SetNewScreen(screen);
|
||||
} else if (GameMode_HandlesKeyDown(key)) {
|
||||
} else if (key == KeyBind_Get(KeyBind_IDOverlay)) {
|
||||
if (Gui_OverlaysCount > 0) return true;
|
||||
Gui_ShowOverlay(new TexIdsOverlay());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputHandler_TouchesSolid(BlockID b) { return Block_Collide[b] == COLLIDE_SOLID; }
|
||||
bool InputHandler_PushbackPlace(AABB* blockBB) {
|
||||
Entity* p = &LocalPlayer_Instance.Base.Base;
|
||||
HacksComp* hacks = &LocalPlayer_Instance.Hacks;
|
||||
Vector3 curPos = p->Position, adjPos = p->Position;
|
||||
|
||||
/* Offset position by the closest face */
|
||||
Face closestFace = Game_SelectedPos.ClosestFace;
|
||||
if (closestFace == FACE_XMAX) {
|
||||
adjPos.X = blockBB->Max.X + 0.5f;
|
||||
} else if (closestFace == FACE_ZMAX) {
|
||||
adjPos.Z = blockBB->Max.Z + 0.5f;
|
||||
} else if (closestFace == FACE_XMIN) {
|
||||
adjPos.X = blockBB->Min.X - 0.5f;
|
||||
} else if (closestFace == FACE_ZMIN) {
|
||||
adjPos.Z = blockBB->Min.Z - 0.5f;
|
||||
} else if (closestFace == FACE_YMAX) {
|
||||
adjPos.Y = blockBB->Min.Y + 1 + ENTITY_ADJUSTMENT;
|
||||
} else if (closestFace == FACE_YMIN) {
|
||||
adjPos.Y = blockBB->Min.Y - p->Size.Y - ENTITY_ADJUSTMENT;
|
||||
}
|
||||
|
||||
/* exclude exact map boundaries, otherwise player can get stuck outside map */
|
||||
bool validPos =
|
||||
adjPos.X > 0.0f && adjPos.Y >= 0.0f && adjPos.Z > 0.0f &&
|
||||
adjPos.X < World_Width && adjPos.Z < World_Length;
|
||||
if (!validPos) return false;
|
||||
|
||||
p->Position = adjPos;
|
||||
AABB bounds; Entity_GetBounds(p, &bounds);
|
||||
if (!hacks->Noclip && Entity_TouchesAny(&bounds, InputHandler_TouchesSolid)) {
|
||||
p->Position = curPos;
|
||||
return false;
|
||||
}
|
||||
|
||||
p->Position = curPos;
|
||||
LocationUpdate update; LocationUpdate_MakePos(&update, adjPos, false);
|
||||
p->VTABLE->SetLocation(p, &update, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputHandler_IntersectsOthers(Vector3 pos, BlockID block) {
|
||||
AABB blockBB;
|
||||
Vector3_Add(&blockBB.Min, &pos, &Block_MinBB[block]);
|
||||
Vector3_Add(&blockBB.Max, &pos, &Block_MaxBB[block]);
|
||||
|
||||
Int32 id;
|
||||
for (id = 0; id < ENTITIES_SELF_ID; id++) {
|
||||
Entity* entity = Entities_List[id];
|
||||
if (entity == NULL) continue;
|
||||
|
||||
AABB bounds; Entity_GetBounds(entity, &bounds);
|
||||
bounds.Min.Y += 1.0f / 32.0f; /* when player is exactly standing on top of ground */
|
||||
if (AABB_Intersects(&bounds, &blockBB)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InputHandler_CheckIsFree(BlockID block) {
|
||||
Vector3 pos; Vector3I_ToVector3(&pos, &Game_SelectedPos.TranslatedPos);
|
||||
Entity* p = &LocalPlayer_Instance.Base.Base;
|
||||
HacksComp* hacks = &LocalPlayer_Instance.Hacks;
|
||||
|
||||
if (Block_Collide[block] != COLLIDE_SOLID) return true;
|
||||
if (InputHandler_IntersectsOthers(pos, block)) return false;
|
||||
Vector3 nextPos = LocalPlayer_Instance.Interp.Next.Pos;
|
||||
|
||||
AABB blockBB;
|
||||
Vector3_Add(&blockBB.Min, &pos, &Block_MinBB[block]);
|
||||
Vector3_Add(&blockBB.Max, &pos, &Block_MaxBB[block]);
|
||||
|
||||
/* NOTE: Need to also test against nextPos here, otherwise player can
|
||||
fall through the block at feet as collision is performed against nextPos */
|
||||
AABB localBB; AABB_Make(&localBB, &p->Position, &p->Size);
|
||||
localBB.Min.Y = min(nextPos.Y, localBB.Min.Y);
|
||||
|
||||
if (hacks->Noclip || !AABB_Intersects(&localBB, &blockBB)) return true;
|
||||
if (hacks->CanPushbackBlocks && hacks->PushbackPlacing && hacks->Enabled) {
|
||||
return InputHandler_PushbackPlace(&blockBB);
|
||||
}
|
||||
|
||||
localBB.Min.Y += 0.25f + ENTITY_ADJUSTMENT;
|
||||
if (AABB_Intersects(&localBB, &blockBB)) return false;
|
||||
|
||||
/* Push player upwards when they are jumping and trying to place a block underneath them */
|
||||
nextPos.Y = pos.Y + Block_MaxBB[block].Y + ENTITY_ADJUSTMENT;
|
||||
LocationUpdate update; LocationUpdate_MakePos(&update, nextPos, false);
|
||||
p->VTABLE->SetLocation(p, &update, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right) {
|
||||
DateTime now = Platform_CurrentUTCTime();
|
||||
Int64 delta = DateTime_MsBetween(&input_lastClick, &now);
|
||||
if (cooldown && delta < 250) return; /* 4 times per second */
|
||||
|
||||
input_lastClick = now;
|
||||
if (ServerConnection_SupportsPlayerClick && !Gui_GetActiveScreen()->HandlesAllInput) {
|
||||
input_pickingId = -1;
|
||||
InputHandler_ButtonStateChanged(MouseButton_Left, left);
|
||||
InputHandler_ButtonStateChanged(MouseButton_Right, right);
|
||||
InputHandler_ButtonStateChanged(MouseButton_Middle, middle);
|
||||
}
|
||||
|
||||
if (Gui_GetActiveScreen()->HandlesAllInput || !Inventory_CanPick) return;
|
||||
|
||||
if (left) {
|
||||
if (GameMode_PickingLeft()) return;
|
||||
Vector3I pos = Game_SelectedPos.BlockPos;
|
||||
if (!Game_SelectedPos.Valid || !World_IsValidPos_3I(pos)) return;
|
||||
|
||||
BlockID old = World_GetBlock_3I(pos);
|
||||
if (Block_Draw[old] == DRAW_GAS || !Block_CanDelete[old]) return;
|
||||
GameMode_PickLeft(old);
|
||||
} else if (right) {
|
||||
if (GameMode_PickingRight()) return;
|
||||
Vector3I pos = Game_SelectedPos.TranslatedPos;
|
||||
if (!Game_SelectedPos.Valid || !World_IsValidPos_3I(pos)) return;
|
||||
|
||||
BlockID old = World_GetBlock_3I(pos);
|
||||
BlockID block = Inventory_SelectedBlock;
|
||||
if (Game_AutoRotate) { block = AutoRotate_RotateBlock(block); }
|
||||
|
||||
if (Game_CanPick(old) || !Block_CanPlace[block]) return;
|
||||
/* air-ish blocks can only replace over other air-ish blocks */
|
||||
if (Block_Draw[block] == DRAW_GAS && Block_Draw[old] != DRAW_GAS) return;
|
||||
|
||||
if (!InputHandler_CheckIsFree(block)) return;
|
||||
GameMode_PickRight(old, block);
|
||||
} else if (middle) {
|
||||
Vector3I pos = Game_SelectedPos.BlockPos;
|
||||
if (!Game_SelectedPos.Valid || !World_IsValidPos_3I(pos)) return;
|
||||
|
||||
BlockID old = World_GetBlock_3I(pos);
|
||||
GameMode_PickMiddle(old);
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler_MouseWheel(void* obj, Real32 delta) {
|
||||
GuiElement* active = &Gui_GetActiveScreen()->Base;
|
||||
if (active->HandlesMouseScroll(active, delta)) return;
|
||||
|
||||
bool hotbar = Key_IsAltPressed() || Key_IsControlPressed() || Key_IsShiftPressed();
|
||||
if (!hotbar && Camera_ActiveCamera->Zoom(delta)) return;
|
||||
if (InputHandler_DoFovZoom(delta) || !Inventory_CanChangeHeldBlock) return;
|
||||
|
||||
game.Gui.hudScreen.hotbar.HandlesMouseScroll(delta);
|
||||
}
|
||||
|
||||
void InputHandler_MouseMove(void* obj, Int32 xDelta, Int32 yDelta) {
|
||||
GuiElement* active = &Gui_GetActiveScreen()->Base;
|
||||
active->HandlesMouseMove(active, Mouse_X, Mouse_Y);
|
||||
}
|
||||
|
||||
void InputHandler_MouseDown(void* obj, MouseButton button) {
|
||||
GuiElement* active = &Gui_GetActiveScreen()->Base;
|
||||
if (!active->HandlesMouseDown(active, Mouse_X, Mouse_Y, button)) {
|
||||
bool left = button == MouseButton_Left;
|
||||
bool middle = button == MouseButton_Middle;
|
||||
bool right = button == MouseButton_Right;
|
||||
InputHandler_PickBlocks(false, left, middle, right);
|
||||
} else {
|
||||
input_lastClick = Platform_CurrentUTCTime();
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler_MouseUp(void* obj, MouseButton button) {
|
||||
GuiElement* active = &Gui_GetActiveScreen()->Base;
|
||||
if (!active->HandlesMouseUp(active, Mouse_X, Mouse_Y, button)) {
|
||||
if (ServerConnection_SupportsPlayerClick && button <= MouseButton_Middle) {
|
||||
input_pickingId = -1;
|
||||
InputHandler_ButtonStateChanged(button, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InputHandler_SimulateMouse(Key key, bool pressed) {
|
||||
Key left = KeyBind_Get(KeyBind_MouseLeft);
|
||||
Key middle = KeyBind_Get(KeyBind_MouseMiddle);
|
||||
Key right = KeyBind_Get(KeyBind_MouseRight);
|
||||
if (!(key == left || key == middle || key == right)) return false;
|
||||
|
||||
MouseButton btn = key == left ? MouseButton_Left : key == middle ? MouseButton_Middle : MouseButton_Right;
|
||||
if (pressed) { InputHandler_MouseDown(NULL, btn); }
|
||||
else { InputHandler_MouseUp(NULL, btn); }
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputHandler_KeyDown(void* obj, Key key) {
|
||||
if (InputHandler_SimulateMouse(key, true)) return;
|
||||
GuiElement* active = &Gui_GetActiveScreen()->Base;
|
||||
|
||||
Key last = input_lastKey; input_lastKey = key;
|
||||
if (InputHandler_IsShutdown(key, last)) {
|
||||
/* TODO: Do we need a separate exit function in Game class? */
|
||||
Window_Close();
|
||||
} else if (key == KeyBind_Get(KeyBind_Screenshot)) {
|
||||
Game_ScreenshotRequested = true;
|
||||
} else if (active->HandlesKeyDown(active, key)) {
|
||||
} else if (InputHandler_HandleCoreKey(key)) {
|
||||
} else if (LocalPlayer_Instance.Input.Handles(key)) {
|
||||
} else {
|
||||
UInt8 textBuffer[String_BufferSize(STRING_SIZE)];
|
||||
String text = String_InitAndClearArray(textBuffer);
|
||||
bool more;
|
||||
if (!Hotkeys_IsHotkey(key, &text, &more)) return;
|
||||
|
||||
if (!more) {
|
||||
ServerConnection_SendChat(&text);
|
||||
} else if (Gui_Active == NULL) {
|
||||
HUDScreen_OpenInput(Gui_HUD, &text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler_KeyUp(void* obj, Key key) {
|
||||
if (InputHandler_SimulateMouse(key, false)) return;
|
||||
|
||||
if (key == KeyBind_Get(KeyBind_ZoomScrolling)) {
|
||||
InputHandler_SetFOV(Game_DefaultFov, false);
|
||||
}
|
||||
|
||||
GuiElement* active = &Gui_GetActiveScreen()->Base;
|
||||
active->HandlesKeyUp(active, key);
|
||||
}
|
||||
|
||||
void InputHandler_KeyPress(void* obj, Int32 keyChar) {
|
||||
GuiElement* active = &Gui_GetActiveScreen()->Base;
|
||||
active->HandlesKeyPress(active, (UInt8)keyChar);
|
||||
}
|
||||
|
||||
void InputHandler_Init(void) {
|
||||
Event_RegisterReal32(&MouseEvents_Wheel, NULL, InputHandler_MouseWheel);
|
||||
Event_RegisterMouseMove(&MouseEvents_Moved, NULL, InputHandler_MouseMove);
|
||||
Event_RegisterInt32(&MouseEvents_Down, NULL, InputHandler_MouseDown);
|
||||
Event_RegisterInt32(&MouseEvents_Up, NULL, InputHandler_MouseUp);
|
||||
Event_RegisterInt32(&KeyEvents_Down, NULL, InputHandler_KeyDown);
|
||||
Event_RegisterInt32(&KeyEvents_Up, NULL, InputHandler_KeyUp);
|
||||
Event_RegisterInt32(&KeyEvents_Press, NULL, InputHandler_KeyPress);
|
||||
|
||||
KeyBind_Init();
|
||||
Hotkeys_Init();
|
||||
}
|
11
src/Client/InputHandler.h
Normal file
11
src/Client/InputHandler.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef CC_INPUTHANDLER_H
|
||||
#define CC_INPUTHANDLER_H
|
||||
#include "Typedefs.h"
|
||||
/* Implements base handlers for mouse and keyboard input.
|
||||
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
|
||||
*/
|
||||
|
||||
bool InputHandler_SetFOV(Int32 fov, bool setZoom);
|
||||
void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right);
|
||||
void InputHandler_Init(void);
|
||||
#endif
|
@ -6,6 +6,7 @@
|
||||
#include "World.h"
|
||||
#include "Funcs.h"
|
||||
#include "Platform.h"
|
||||
#include "BlockID.h"
|
||||
|
||||
Real32 PickedPos_dist;
|
||||
void PickedPos_TestAxis(PickedPos* pos, Real32 dAxis, Face fAxis) {
|
||||
|
@ -3,29 +3,20 @@
|
||||
#include "Typedefs.h"
|
||||
#include "Constants.h"
|
||||
#include "Vectors.h"
|
||||
#include "BlockID.h"
|
||||
/* Data for picking/selecting block by the user, and clipping the camera.
|
||||
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
|
||||
*/
|
||||
|
||||
/* Describes the picked/selected block by the user and its position. */
|
||||
typedef struct PickedPos_ {
|
||||
/* Minimum world coordinates of the block's bounding box.*/
|
||||
Vector3 Min;
|
||||
/* Maximum world coordinates of the block's bounding box. */
|
||||
Vector3 Max;
|
||||
/* Exact world coordinates at which the ray intersected this block. */
|
||||
Vector3 Intersect;
|
||||
/* Integer world coordinates of the block. */
|
||||
Vector3I BlockPos;
|
||||
/* Integer world coordinates of the neighbouring block that is closest to the player. */
|
||||
Vector3I TranslatedPos;
|
||||
/* Whether this instance actually has a selected block currently. */
|
||||
bool Valid;
|
||||
/* Face of the picked block that is closet to the player. */
|
||||
Face ClosestFace;
|
||||
/* Block ID of the picked block. */
|
||||
BlockID Block;
|
||||
Vector3 Min; /* Minimum coords of the block's bounding box.*/
|
||||
Vector3 Max; /* Maximum coords of the block's bounding box. */
|
||||
Vector3 Intersect; /* Coords at which the ray intersected this block. */
|
||||
Vector3I BlockPos; /* Coords of the block */
|
||||
Vector3I TranslatedPos; /* Coords of the neighbouring block that is closest to the player */
|
||||
bool Valid; /* Whether this instance actually has a selected block currently */
|
||||
Face ClosestFace; /* Face of the picked block that is closet to the player */
|
||||
BlockID Block; /* Block ID of the picked block */
|
||||
} PickedPos;
|
||||
|
||||
/* Implements a voxel ray tracer
|
||||
@ -46,9 +37,7 @@ typedef struct RayTracer_ {
|
||||
Vector3 tMax, tDelta;
|
||||
} RayTracer;
|
||||
|
||||
/* Mark as having a selected block, and calculates the closest face of the selected block's position. */
|
||||
void PickedPos_SetAsValid(PickedPos* pos, RayTracer* t, Vector3 intersect);
|
||||
/* Marks as not having a selected block. */
|
||||
void PickedPos_SetAsInvalid(PickedPos* pos);
|
||||
void RayTracer_SetVectors(RayTracer* t, Vector3 origin, Vector3 dir);
|
||||
void RayTracer_Step(RayTracer* t);
|
||||
|
@ -1651,4 +1651,9 @@ IGameComponent HUDScreen_MakeComponent(void) {
|
||||
IGameComponent comp = IGameComponent_MakeEmpty();
|
||||
comp.Ready = HUDScreen_Ready;
|
||||
return comp;
|
||||
}
|
||||
|
||||
void HUDScreen_OpenInput(Screen* hud, STRING_PURE String* text) {
|
||||
Screen* chat = ((HUDScreen*)hud)->Chat;
|
||||
ChatScreen_OpenInput((ChatScreen*)chat, text);
|
||||
}
|
@ -15,6 +15,7 @@ Screen* LoadingScreen_MakeInstance(STRING_PURE String* title, STRING_PURE String
|
||||
Screen* GeneratingScreen_MakeInstance(void);
|
||||
Screen* HUDScreen_MakeInstance(void);
|
||||
IGameComponent HUDScreen_MakeComponent(void);
|
||||
void HUDScreen_OpenInput(Screen* hud, STRING_PURE String* text);
|
||||
|
||||
Screen* OptionsGroupScreen_MakeInstance(void);
|
||||
Screen* PauseScreen_MakeInstance(void);
|
||||
|
@ -2,10 +2,9 @@
|
||||
#define CC_SERVERCONNECTION_H
|
||||
#include "Typedefs.h"
|
||||
#include "String.h"
|
||||
#include "Vectors.h"
|
||||
#include "Input.h"
|
||||
#include "GameStructs.h"
|
||||
#include "PickedPosRenderer.h"
|
||||
#include "Picking.h"
|
||||
/* Represents a connection to either a singleplayer or multiplayer server.
|
||||
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
|
||||
*/
|
||||
|
@ -25,10 +25,7 @@ Texture Texture_From(GfxResourceID id, Int32 x, Int32 y, Int32 width, Int32 heig
|
||||
}
|
||||
|
||||
Texture Texture_MakeInvalid(void) {
|
||||
Texture tex;
|
||||
tex.ID = NULL;
|
||||
tex.X = 0; tex.Y = 0; tex.Width = 0; tex.Height = 0;
|
||||
tex.U1 = 0.0f; tex.V1 = 0.0f; tex.U2 = 0.0f; tex.V2 = 0.0f;
|
||||
Texture tex = { NULL, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
return tex;
|
||||
}
|
||||
|
||||
|
@ -18,17 +18,11 @@ typedef struct Texture_ {
|
||||
Real32 U2, V2; /* Texture coordinates of bottom right corner. */
|
||||
} Texture;
|
||||
|
||||
/* Creates a texture, with U1 and V1 being set to 0. */
|
||||
Texture Texture_FromOrigin(GfxResourceID id, Int32 x, Int32 y, Int32 width, Int32 height, Real32 u2, Real32 v2);
|
||||
/* Creates a texture, with U1/V1/U2/V2 using the input rectangle. */
|
||||
Texture Texture_FromRec(GfxResourceID id, Int32 x, Int32 y, Int32 width, Int32 height, TextureRec rec);
|
||||
/* Creates a texture. */
|
||||
Texture Texture_From(GfxResourceID id, Int32 x, Int32 y, Int32 width, Int32 height, Real32 u1, Real32 u2, Real32 v1, Real32 v2);
|
||||
/* Makes an invalid texture. */
|
||||
Texture Texture_MakeInvalid(void);
|
||||
|
||||
/* Renders this texture to the screen. */
|
||||
void Texture_Render(Texture* tex);
|
||||
/* Renders this texture to the screen, with the given colour as a shade. */
|
||||
void Texture_RenderShaded(Texture* tex, PackedCol shadeCol);
|
||||
#endif
|
@ -49,11 +49,10 @@ bool Utils_IsValidInputChar(UInt8 c, bool supportsCP437) {
|
||||
}
|
||||
|
||||
bool Utils_IsUrlPrefix(STRING_PURE String* value, Int32 index) {
|
||||
String httpStr = String_FromConst("http://");
|
||||
String httpsStr = String_FromConst("https://");
|
||||
Int32 http = String_IndexOfString(value, &httpStr);
|
||||
Int32 https = String_IndexOfString(value, &httpsStr);
|
||||
return http == index || https == index;
|
||||
String http = String_FromConst("http://");
|
||||
String https = String_FromConst("https://");
|
||||
return String_IndexOfString(value, &http) == index
|
||||
|| String_IndexOfString(value, &https) == index;
|
||||
}
|
||||
|
||||
Int32 Utils_AccumulateWheelDelta(Real32* accmulator, Real32 delta) {
|
||||
@ -74,11 +73,4 @@ UInt8 Utils_GetSkinType(Bitmap* bmp) {
|
||||
UInt32 pixel = Bitmap_GetPixel(bmp, 54 * scale, 20 * scale);
|
||||
UInt8 alpha = (UInt8)(pixel >> 24);
|
||||
return alpha >= 127 ? SKIN_TYPE_64x64 : SKIN_TYPE_64x64_SLIM;
|
||||
}
|
||||
|
||||
bool Utils_IsUrlPrefix(STRING_PURE String* str, Int32 index) {
|
||||
String http = String_FromConst("http://");
|
||||
String https = String_FromConst("https://");
|
||||
return String_IndexOfString(str, &http) == index
|
||||
|| String_IndexOfString(str, &https) == index;
|
||||
}
|
@ -34,5 +34,4 @@ Int32 Utils_AccumulateWheelDelta(Real32* accmulator, Real32 delta);
|
||||
#define Utils_AdjViewDist(value) ((Int32)(1.4142135f * (value)))
|
||||
|
||||
UInt8 Utils_GetSkinType(Bitmap* bmp);
|
||||
bool Utils_IsUrlPrefix(STRING_PURE String* str, Int32 index);
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user