private void UpdatePicking()
{
bool left = Mouse[OpenTK.Input.MouseButton.Left];//destruct
bool middle = Mouse[OpenTK.Input.MouseButton.Middle];//clone material as active
bool right = Mouse[OpenTK.Input.MouseButton.Right];//build
if (!leftpressedpicking)
{
if (mouseleftclick)
{
leftpressedpicking = true;
}
else
{
left = false;
}
}
else
{
if (mouseleftdeclick)
{
leftpressedpicking = false;
left = false;
}
}
if (!left)
{
currentAttackedBlock = null;
}
float pick_distance = PICK_DISTANCE;
if (cameratype == CameraType.Tpp) { pick_distance = tppcameradistance * 2; }
if (cameratype == CameraType.Overhead) { pick_distance = overheadcameradistance; }
float unit_x = 0;
float unit_y = 0;
int NEAR = 1;
int FOV = 600;
float ASPECT = 640f / 480;
float near_height = NEAR * (float)(Math.Tan(FOV * Math.PI / 360.0));
Vector3 ray = new Vector3(unit_x * near_height * ASPECT, unit_y * near_height, 1);//, 0);
Vector3 ray_start_point = new Vector3(0, 0, 0);
if (overheadcamera)
{
float mx = (float)mouse_current.X / Width - 0.5f;
float my = (float)mouse_current.Y / Height - 0.5f;
//ray_start_point = new Vector3(mx * 1.4f, -my * 1.1f, 0.0f);
ray_start_point = new Vector3(mx * 3f, -my * 2.2f, -1.0f);
}
//Matrix4 the_modelview;
//Read the current modelview matrix into the array the_modelview
//GL.GetFloat(GetPName.ModelviewMatrix, out the_modelview);
if (d_The3d.ModelViewMatrix.Equals(new Matrix4())) { return; }
Matrix4 theModelView = d_The3d.ModelViewMatrix;
theModelView.Invert();
//the_modelview = new Matrix4();
ray = Vector3.Transform(ray, theModelView);
ray_start_point = Vector3.Transform(ray_start_point, theModelView);
Line3D pick = new Line3D();
Vector3 raydir = -(ray - ray_start_point);
raydir.Normalize();
pick.Start = ray + Vector3.Multiply(raydir, 1f); //do not pick behind
pick.End = ray + Vector3.Multiply(raydir, pick_distance * 2);
//pick models
selectedmodelid = -1;
foreach (var m in Models)
{
Vector3 closestmodelpos = new Vector3(int.MaxValue, int.MaxValue, int.MaxValue);
foreach (var t in m.TrianglesForPicking)
{
Vector3 intersection;
if (Collisions.Intersection.RayTriangle(pick, t, out intersection) == 1)
{
if ((pick.Start - intersection).Length > pick_distance)
{
continue;
}
if ((pick.Start - intersection).Length < (pick.Start - closestmodelpos).Length)
{
closestmodelpos = intersection;
selectedmodelid = m.Id;
}
}
}
}
if (selectedmodelid != -1)
{
pickcubepos = new Vector3(-1, -1, -1);
if (mouseleftclick)
{
ModelClick(selectedmodelid);
}
mouseleftclick = false;
leftpressedpicking = false;
return;
}
if (left)
{
d_Weapon.SetAttack(true, false);
}
else if (right)
{
d_Weapon.SetAttack(true, true);
}
//if (iii++ % 2 == 0)
{
//To improve speed, update picking only every second frame.
//return;
}
//pick terrain
var s = new BlockOctreeSearcher();
s.StartBox = new Box3D(0, 0, 0, BitTools.NextPowerOfTwo((uint)Math.Max(d_Map.MapSizeX, Math.Max(d_Map.MapSizeY, d_Map.MapSizeZ))));
List<BlockPosSide> pick2 = new List<BlockPosSide>(s.LineIntersection(IsTileEmptyForPhysics, getblockheight, pick));
pick2.Sort((a, b) => { return (a.pos - ray_start_point).Length.CompareTo((b.pos - ray_start_point).Length); });
if (overheadcamera && pick2.Count > 0 && left)
{
//if not picked any object, and mouse button is pressed, then walk to destination.
playerdestination = pick2[0].pos;
}
bool pickdistanceok = pick2.Count > 0 && (pick2[0].pos - (player.playerposition)).Length <= pick_distance;
bool playertileempty = IsTileEmptyForPhysics(
(int)ToMapPos(player.playerposition).X,
(int)ToMapPos(player.playerposition).Y,
(int)ToMapPos(player.playerposition).Z);
bool playertileemptyclose = IsTileEmptyForPhysicsClose(
(int)ToMapPos(player.playerposition).X,
(int)ToMapPos(player.playerposition).Y,
(int)ToMapPos(player.playerposition).Z);
BlockPosSide pick0;
if (pick2.Count > 0 &&
((pickdistanceok && (playertileempty || (playertileemptyclose)))
|| overheadcamera)
)
{
pickcubepos = pick2[0].Current();
pickcubepos = new Vector3((int)pickcubepos.X, (int)pickcubepos.Y, (int)pickcubepos.Z);
pick0 = pick2[0];
}
else
{
pickcubepos = new Vector3(-1, -1, -1);
pick0.pos = new Vector3(-1, -1, -1);
pick0.side = TileSide.Front;
}
if (FreeMouse)
{
if (pick2.Count > 0)
{
OnPick(pick0);
}
return;
}
var ntile = pick0.Current();
if(IsUsableBlock(d_Map.GetBlock((int)ntile.X, (int)ntile.Z, (int)ntile.Y))) {
currentAttackedBlock = new Vector3i((int)ntile.X, (int)ntile.Z, (int)ntile.Y);
}
if ((DateTime.Now - lastbuild).TotalSeconds >= BuildDelay)
{
if (left && d_Inventory.RightHand[ActiveMaterial] == null) {
PacketClientHealth p = new PacketClientHealth { CurrentHealth = (int)(2 + rnd.NextDouble() * 4) };
SendPacket(Serialize(new PacketClient() { PacketId = ClientPacketId.MonsterHit, Health = p }));
}
if (left && !fastclicking)
{
//todo animation
fastclicking = false;
}
if (left || right || middle)
{
lastbuild = DateTime.Now;
}
if (pick2.Count > 0)
{
if (middle)
{
var newtile = pick0.Current();
if (MapUtil.IsValidPos(d_Map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y))
{
int clonesource = d_Map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y);
int clonesource2 = (int)d_Data.WhenPlayerPlacesGetsConvertedTo[(int)clonesource];
//find this block in another right hand.
for (int i = 0; i < 10; i++)
{
if (d_Inventory.RightHand[i] != null
&& d_Inventory.RightHand[i].ItemClass == ItemClass.Block
&& (int)d_Inventory.RightHand[i].BlockId == clonesource2)
{
ActiveMaterial = i;
goto done;
}
}
int? freehand = d_InventoryUtil.FreeHand(ActiveMaterial);
//find this block in inventory.
foreach (var k in d_Inventory.Items)
{
if (k.Value.ItemClass == ItemClass.Block
&& k.Value.BlockId == clonesource2)
{
//free hand
if (freehand != null)
{
d_InventoryController.WearItem(
InventoryPosition.MainArea(k.Key.ToPoint()),
InventoryPosition.MaterialSelector(freehand.Value));
goto done;
}
//try to replace current slot
if (d_Inventory.RightHand[ActiveMaterial] != null
&& d_Inventory.RightHand[ActiveMaterial].ItemClass == ItemClass.Block)
{
d_InventoryController.MoveToInventory(
InventoryPosition.MaterialSelector(ActiveMaterial));
d_InventoryController.WearItem(
InventoryPosition.MainArea(k.Key.ToPoint()),
InventoryPosition.MaterialSelector(ActiveMaterial));
}
}
}
done:
d_Audio.Play(d_Data.CloneSound[clonesource][0]); //todo sound cycle
}
}
if (left || right)
{
BlockPosSide tile = pick0;
Console.Write(tile.pos + ":" + Enum.GetName(typeof(TileSide), tile.side));
Vector3 newtile = right ? tile.Translated() : tile.Current();
if (MapUtil.IsValidPos(d_Map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y))
{
Console.WriteLine(". newtile:" + newtile + " type: " + d_Map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y));
if (pick0.pos != new Vector3(-1, -1, -1))
{
int blocktype;
if (left) { blocktype = d_Map.GetBlock((int)newtile.X, (int)newtile.Z, (int)newtile.Y); }
else { blocktype = materialSlots[ActiveMaterial]; }
if (left && blocktype == d_Data.BlockIdAdminium) { goto end; }
string[] sound = left ? d_Data.BreakSound[blocktype] : d_Data.BuildSound[blocktype];
if (sound != null && sound.Length > 0)
{
d_Audio.Play(sound[0]); //todo sound cycle
}
}
//normal attack
if (!right)
{
//attack
var pos = new Vector3i((int)newtile.X, (int)newtile.Z, (int)newtile.Y);
currentAttackedBlock = new Vector3i(pos.x,pos.y,pos.z);
if (!blockhealth.ContainsKey(pos))
{
blockhealth[pos] = GetCurrentBlockHealth(pos.x, pos.y, pos.z);
}
blockhealth[pos] -= WeaponAttackStrength();
float health = GetCurrentBlockHealth(pos.x,pos.y,pos.z);
if (health <= 0)
{
if (currentAttackedBlock != null)
{
blockhealth.Remove(currentAttackedBlock.Value);
}
currentAttackedBlock = null;
goto broken;
}
goto end;
}
if (!right)
{
particleEffectBlockBreak.StartParticleEffect(newtile);//must be before deletion - gets ground type.
}
if (!MapUtil.IsValidPos(d_Map, (int)newtile.X, (int)newtile.Z, (int)newtile.Y))
{
throw new Exception();
}
broken:
OnPick(new Vector3((int)newtile.X, (int)newtile.Z, (int)newtile.Y),
new Vector3((int)tile.Current().X, (int)tile.Current().Z, (int)tile.Current().Y), tile.pos,
right);
//network.SendSetBlock(new Vector3((int)newtile.X, (int)newtile.Z, (int)newtile.Y),
// right ? BlockSetMode.Create : BlockSetMode.Destroy, (byte)MaterialSlots[activematerial]);
}
}
}
}
end:
fastclicking = false;
if (!(left || right || middle))
{
lastbuild = new DateTime();
fastclicking = true;
}
}