mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 20:16:36 -04:00
Gun no longer runs on separate thread. Fixes #449.
This commit is contained in:
parent
4b2eb16806
commit
163638e8b5
@ -19,8 +19,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using MCGalaxy.Maths;
|
||||
using MCGalaxy.Tasks;
|
||||
|
||||
namespace MCGalaxy.Commands.Fun {
|
||||
namespace MCGalaxy.Commands.Fun {
|
||||
public sealed class CmdGun : WeaponCmd {
|
||||
public override string name { get { return "gun"; } }
|
||||
protected override string Weapon { get { return "Gun"; } }
|
||||
@ -29,70 +30,80 @@ namespace MCGalaxy.Commands.Fun {
|
||||
p.RevertBlock(x, y, z);
|
||||
if (!CommandParser.IsBlockAllowed(p, "place", block)) return;
|
||||
|
||||
Thread gunThread = new Thread(() => DoShoot(p, block));
|
||||
gunThread.Name = "MCG_Gun";
|
||||
gunThread.Start();
|
||||
WeaponArgs args = new WeaponArgs();
|
||||
args.player = p;
|
||||
args.block = block;
|
||||
args.weaponType = (WeaponType)p.blockchangeObject;
|
||||
|
||||
args.start = MakePos(p);
|
||||
args.dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX);
|
||||
args.pos = args.PosAt(3);
|
||||
args.iterations = 4;
|
||||
|
||||
SchedulerTask task = new SchedulerTask(GunCallback, args, TimeSpan.Zero, true);
|
||||
p.CriticalTasks.Add(task);
|
||||
}
|
||||
|
||||
void DoShoot(Player p, ExtBlock block) {
|
||||
CatchPos bp = (CatchPos)p.blockchangeObject;
|
||||
Vec3F32 dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX);
|
||||
static void GunCallback(SchedulerTask task) {
|
||||
WeaponArgs args = (WeaponArgs)task.State;
|
||||
if (args.moving) {
|
||||
args.moving = MoveGun(args);
|
||||
|
||||
// Laser gun persists for a short while
|
||||
if (!args.moving && args.weaponType == WeaponType.Laser)
|
||||
task.Delay = TimeSpan.FromMilliseconds(400);
|
||||
return;
|
||||
}
|
||||
|
||||
double bigDiag = Math.Sqrt(Math.Sqrt(p.level.Width * p.level.Width + p.level.Length * p.level.Length)
|
||||
+ p.level.Height * p.level.Height + p.level.Width * p.level.Width);
|
||||
args.TeleportSourcePlayer();
|
||||
if (args.weaponType == WeaponType.Laser) {
|
||||
foreach (Vec3U16 pos in args.previous) {
|
||||
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
|
||||
}
|
||||
args.previous.Clear();
|
||||
} else if (args.previous.Count > 0) {
|
||||
Vec3U16 pos = args.previous[0];
|
||||
args.previous.RemoveAt(0);
|
||||
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
|
||||
}
|
||||
task.Repeating = args.previous.Count > 0;
|
||||
}
|
||||
|
||||
static bool MoveGun(WeaponArgs args) {
|
||||
while (true) {
|
||||
args.pos = args.PosAt(args.iterations);
|
||||
args.iterations++;
|
||||
Vec3U16 pos = args.pos;
|
||||
|
||||
List<Vec3U16> previous = new List<Vec3U16>();
|
||||
List<Vec3U16> allBlocks = new List<Vec3U16>();
|
||||
Vec3U16 pos;
|
||||
|
||||
Vec3S32 start = p.Pos.BlockCoords;
|
||||
pos.X = (ushort)Math.Round(start.X + dir.X * 3);
|
||||
pos.Y = (ushort)Math.Round(start.Y + dir.Y * 3);
|
||||
pos.Z = (ushort)Math.Round(start.Z + dir.Z * 3);
|
||||
ExtBlock cur = args.player.level.GetBlock(pos.X, pos.Y, pos.Z);
|
||||
if (cur.IsInvalid) return false;
|
||||
if (cur.BlockID != Block.air && !args.allBlocks.Contains(pos) && HandlesHitBlock(args.player, cur, args.weaponType, pos, true))
|
||||
return false;
|
||||
|
||||
for (double t = 4; bigDiag > t; t++) {
|
||||
pos.X = (ushort)Math.Round(start.X + (double)(dir.X * t));
|
||||
pos.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * t));
|
||||
pos.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * t));
|
||||
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, args.block);
|
||||
args.previous.Add(pos);
|
||||
args.allBlocks.Add(pos);
|
||||
if (HitsPlayer(args, pos)) return false;
|
||||
|
||||
ExtBlock cur = p.level.GetBlock(pos.X, pos.Y, pos.Z);
|
||||
if (cur.BlockID != Block.air && !allBlocks.Contains(pos) && HandlesHitBlock(p, cur, bp.ending, pos, true))
|
||||
break;
|
||||
|
||||
p.level.Blockchange(pos.X, pos.Y, pos.Z, block);
|
||||
previous.Add(pos);
|
||||
allBlocks.Add(pos);
|
||||
|
||||
if (HandlesPlayers(p, bp, pos)) break;
|
||||
|
||||
if (t > 12 && bp.ending != EndType.Laser) {
|
||||
pos = previous[0];
|
||||
p.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
|
||||
previous.RemoveAt(0);
|
||||
if (args.iterations > 12 && args.weaponType != WeaponType.Laser) {
|
||||
pos = args.previous[0];
|
||||
args.previous.RemoveAt(0);
|
||||
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
|
||||
}
|
||||
|
||||
if (bp.ending != EndType.Laser) Thread.Sleep(20);
|
||||
}
|
||||
|
||||
if (bp.ending == EndType.Teleport) {
|
||||
int index = previous.Count - 3;
|
||||
if (index >= 0 && index < previous.Count)
|
||||
DoTeleport(p, previous[index]);
|
||||
}
|
||||
if (bp.ending == EndType.Laser) Thread.Sleep(400);
|
||||
|
||||
foreach (Vec3U16 pos1 in previous) {
|
||||
p.level.Blockchange(pos1.X, pos1.Y, pos1.Z, ExtBlock.Air, true);
|
||||
if (bp.ending != EndType.Laser) Thread.Sleep(20);
|
||||
if (args.weaponType != WeaponType.Laser) return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool HandlesPlayers(Player p, CatchPos bp, Vec3U16 pos) {
|
||||
Player pl = GetPlayer(p, pos, true);
|
||||
static Vec3U16 MakePos(Player p) { return (Vec3U16)p.Pos.BlockCoords; }
|
||||
|
||||
static bool HitsPlayer(WeaponArgs args, Vec3U16 pos) {
|
||||
Player pl = GetPlayer(args.player, pos, true);
|
||||
if (pl == null) return false;
|
||||
|
||||
ExtBlock stone = (ExtBlock)Block.stone;
|
||||
if (p.level.physics >= 3 && bp.ending >= EndType.Explode) {
|
||||
Player p = args.player;
|
||||
if (p.level.physics >= 3 && args.weaponType >= WeaponType.Explode) {
|
||||
pl.HandleDeath(stone, " was blown up by " + p.ColoredName, true);
|
||||
} else {
|
||||
pl.HandleDeath(stone, " was shot by " + p.ColoredName);
|
||||
|
@ -35,127 +35,102 @@ namespace MCGalaxy.Commands.Fun {
|
||||
p.RevertBlock(x, y, z);
|
||||
if (!CommandParser.IsBlockAllowed(p, "place", block)) return;
|
||||
|
||||
MissileArgs args = new MissileArgs();
|
||||
WeaponArgs args = new WeaponArgs();
|
||||
args.player = p;
|
||||
args.block = block;
|
||||
CatchPos bp = (CatchPos)p.blockchangeObject;
|
||||
args.ending = bp.ending;
|
||||
args.weaponType = (WeaponType)p.blockchangeObject;
|
||||
args.pos = MakePos(p);
|
||||
|
||||
SchedulerTask task = new SchedulerTask(MissileCallback, args,
|
||||
TimeSpan.FromMilliseconds(100), true);
|
||||
p.CriticalTasks.Add(task);
|
||||
}
|
||||
|
||||
class MissileArgs {
|
||||
public Player player;
|
||||
public ExtBlock block;
|
||||
public EndType ending;
|
||||
public Vec3U16 pos;
|
||||
public bool Moving = true;
|
||||
|
||||
public List<Vec3U16> previous = new List<Vec3U16>();
|
||||
public List<Vec3U16> allBlocks = new List<Vec3U16>();
|
||||
public List<Vec3S32> buffer = new List<Vec3S32>();
|
||||
public int iterations;
|
||||
}
|
||||
|
||||
static void MissileCallback(SchedulerTask task) {
|
||||
MissileArgs args = (MissileArgs)task.State;
|
||||
Player p = args.player;
|
||||
if (args.Moving) { PerformMove(args); return; }
|
||||
|
||||
if (args.ending == EndType.Teleport) {
|
||||
args.ending = EndType.Normal;
|
||||
int index = args.previous.Count - 3;
|
||||
if (index >= 0 && index < args.previous.Count)
|
||||
DoTeleport(p, args.previous[index]);
|
||||
}
|
||||
WeaponArgs args = (WeaponArgs)task.State;
|
||||
if (args.moving) { PerformMove(args); return; }
|
||||
|
||||
args.TeleportSourcePlayer();
|
||||
if (args.previous.Count > 0) {
|
||||
Vec3U16 pos = args.previous[0];
|
||||
args.previous.RemoveAt(0);
|
||||
p.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
|
||||
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
|
||||
}
|
||||
task.Repeating = args.previous.Count > 0;
|
||||
}
|
||||
|
||||
static void PerformMove(MissileArgs args) {
|
||||
static void PerformMove(WeaponArgs args) {
|
||||
while (true) {
|
||||
args.iterations++;
|
||||
Vec3U16 target = MissileTarget(args);
|
||||
FindNext(target, ref args.pos, args.buffer);
|
||||
|
||||
if (args.iterations <= 3) continue;
|
||||
args.Moving = MoveMissile(args, args.pos, target);
|
||||
args.moving = MoveMissile(args, args.pos, target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Vec3U16 MissileTarget(MissileArgs args) {
|
||||
static Vec3U16 MissileTarget(WeaponArgs args) {
|
||||
Player p = args.player;
|
||||
Vec3U16 start = MakePos(p);
|
||||
Vec3F32 dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX);
|
||||
Vec3U16 target;
|
||||
args.start = MakePos(p);
|
||||
args.dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX);
|
||||
int i;
|
||||
|
||||
for (i = 1; ; i++) {
|
||||
target.X = (ushort)Math.Round(start.X + (double)(dir.X * i));
|
||||
target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * i));
|
||||
target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * i));
|
||||
|
||||
Vec3U16 target = args.PosAt(i);
|
||||
ExtBlock block = p.level.GetBlock(target.X, target.Y, target.Z);
|
||||
if (block.BlockID == Block.Invalid) break;
|
||||
|
||||
if (block.BlockID != Block.air && !args.allBlocks.Contains(target) && HandlesHitBlock(p, block, args.ending, target, false))
|
||||
if (block.BlockID != Block.air && !args.allBlocks.Contains(target) && HandlesHitBlock(p, block, args.weaponType, target, false))
|
||||
break;
|
||||
|
||||
Player hit = GetPlayer(p, target, true);
|
||||
if (hit != null) return MakePos(hit);
|
||||
}
|
||||
|
||||
target.X = (ushort)Math.Round(start.X + (double)(dir.X * (i - 1)));
|
||||
target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * (i - 1)));
|
||||
target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * (i - 1)));
|
||||
return target;
|
||||
return args.PosAt(i - 1);
|
||||
}
|
||||
|
||||
static bool MoveMissile(MissileArgs args, Vec3U16 pos, Vec3U16 target) {
|
||||
static bool MoveMissile(WeaponArgs args, Vec3U16 pos, Vec3U16 target) {
|
||||
Player p = args.player;
|
||||
ExtBlock block = p.level.GetBlock(pos.X, pos.Y, pos.Z);
|
||||
if (block.BlockID != Block.air && !args.allBlocks.Contains(pos) && HandlesHitBlock(p, block, args.ending, pos, true))
|
||||
if (block.BlockID != Block.air && !args.allBlocks.Contains(pos) && HandlesHitBlock(p, block, args.weaponType, pos, true))
|
||||
return false;
|
||||
|
||||
p.level.Blockchange(pos.X, pos.Y, pos.Z, args.block);
|
||||
args.previous.Add(pos);
|
||||
args.allBlocks.Add(pos);
|
||||
if (HitsPlayer(args, pos)) return false;
|
||||
|
||||
Player hitP = GetPlayer(p, pos, true);
|
||||
if (hitP != null) {
|
||||
if (p.level.physics >= 3 && args.ending >= EndType.Explode) {
|
||||
hitP.HandleDeath((ExtBlock)Block.stone, " was blown up by " + p.ColoredName, true);
|
||||
} else {
|
||||
hitP.HandleDeath((ExtBlock)Block.stone, " was hit a missile from " + p.ColoredName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pos == target && p.level.physics >= 3 && args.ending >= EndType.Explode) {
|
||||
if (pos == target && p.level.physics >= 3 && args.weaponType >= WeaponType.Explode) {
|
||||
p.level.MakeExplosion(target.X, target.Y, target.Z, 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.previous.Count > 12) {
|
||||
p.level.Blockchange(args.previous[0].X, args.previous[0].Y, args.previous[0].Z, ExtBlock.Air, true);
|
||||
pos = args.previous[0];
|
||||
p.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
|
||||
args.previous.RemoveAt(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HitsPlayer(WeaponArgs args, Vec3U16 pos) {
|
||||
Player pl = GetPlayer(args.player, pos, true);
|
||||
if (pl == null) return false;
|
||||
|
||||
ExtBlock stone = (ExtBlock)Block.stone;
|
||||
Player p = args.player;
|
||||
if (p.level.physics >= 3 && args.weaponType >= WeaponType.Explode) {
|
||||
pl.HandleDeath(stone, " was blown up by " + p.ColoredName, true);
|
||||
} else {
|
||||
pl.HandleDeath(stone, " was hit by a missile from " + p.ColoredName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static Vec3U16 MakePos(Player p) {
|
||||
return (Vec3U16)p.Pos.BlockCoords;
|
||||
}
|
||||
static Vec3U16 MakePos(Player p) { return (Vec3U16)p.Pos.BlockCoords; }
|
||||
|
||||
static void FindNext(Vec3U16 lookedAt, ref Vec3U16 pos, List<Vec3S32> buffer) {
|
||||
LineDrawOp.DrawLine(pos.X, pos.Y, pos.Z, 2, lookedAt.X, lookedAt.Y, lookedAt.Z, buffer);
|
||||
|
@ -44,10 +44,10 @@ namespace MCGalaxy.Commands.Fun {
|
||||
return;
|
||||
}
|
||||
|
||||
CatchPos cpos = default(CatchPos);
|
||||
cpos.ending = GetEnd(p, message);
|
||||
if (cpos.ending == EndType.Invalid) return;
|
||||
p.blockchangeObject = cpos;
|
||||
WeaponType weaponType = GetWeaponType(p, message);
|
||||
if (weaponType == WeaponType.Invalid) return;
|
||||
|
||||
p.blockchangeObject = weaponType;
|
||||
p.ClearBlockchange();
|
||||
p.Blockchange += PlacedMark;
|
||||
|
||||
@ -61,15 +61,15 @@ namespace MCGalaxy.Commands.Fun {
|
||||
p.CriticalTasks.Add(task);
|
||||
}
|
||||
|
||||
EndType GetEnd(Player p, string mode) {
|
||||
if (mode == "") return EndType.Normal;
|
||||
if (mode.CaselessEq("destroy")) return EndType.Destroy;
|
||||
if (mode.CaselessEq("tp") || mode.CaselessEq("teleport")) return EndType.Teleport;
|
||||
if (mode.CaselessEq("explode")) return EndType.Explode;
|
||||
if (mode.CaselessEq("laser")) return EndType.Laser;
|
||||
WeaponType GetWeaponType(Player p, string mode) {
|
||||
if (mode == "") return WeaponType.Normal;
|
||||
if (mode.CaselessEq("destroy")) return WeaponType.Destroy;
|
||||
if (mode.CaselessEq("tp") || mode.CaselessEq("teleport")) return WeaponType.Teleport;
|
||||
if (mode.CaselessEq("explode")) return WeaponType.Explode;
|
||||
if (mode.CaselessEq("laser")) return WeaponType.Laser;
|
||||
|
||||
Help(p);
|
||||
return EndType.Invalid;
|
||||
return WeaponType.Invalid;
|
||||
}
|
||||
|
||||
class AimState {
|
||||
@ -137,6 +137,42 @@ namespace MCGalaxy.Commands.Fun {
|
||||
|
||||
protected abstract void PlacedMark(Player p, ushort x, ushort y, ushort z, ExtBlock block);
|
||||
|
||||
|
||||
protected class WeaponArgs {
|
||||
public Player player;
|
||||
public ExtBlock block;
|
||||
public WeaponType weaponType;
|
||||
public Vec3U16 pos, start;
|
||||
public Vec3F32 dir;
|
||||
public bool moving = true;
|
||||
|
||||
public List<Vec3U16> previous = new List<Vec3U16>();
|
||||
public List<Vec3U16> allBlocks = new List<Vec3U16>();
|
||||
public List<Vec3S32> buffer = new List<Vec3S32>();
|
||||
public int iterations;
|
||||
|
||||
public Vec3U16 PosAt(int i) {
|
||||
Vec3U16 target;
|
||||
target.X = (ushort)Math.Round(start.X + (double)(dir.X * i));
|
||||
target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * i));
|
||||
target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * i));
|
||||
return target;
|
||||
}
|
||||
|
||||
public void TeleportSourcePlayer() {
|
||||
if (weaponType != WeaponType.Teleport) return;
|
||||
weaponType = WeaponType.Normal;
|
||||
|
||||
int index = previous.Count - 3;
|
||||
if (index >= 0 && index < previous.Count) {
|
||||
Vec3U16 coords = previous[index];
|
||||
Position pos = new Position(coords.X * 32, coords.Y * 32 + 32, coords.Z * 32);
|
||||
player.SendPos(Entities.SelfID, pos, player.Rot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static Player GetPlayer(Player p, Vec3U16 pos, bool skipSelf) {
|
||||
Player[] players = PlayerInfo.Online.Items;
|
||||
foreach (Player pl in players) {
|
||||
@ -153,18 +189,10 @@ namespace MCGalaxy.Commands.Fun {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static void DoTeleport(Player p, Vec3U16 coords) {
|
||||
try {
|
||||
Position pos = new Position(coords.X * 32, coords.Y * 32 + 32, coords.Z * 32);
|
||||
p.SendPos(Entities.SelfID, pos, p.Rot);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
protected static bool HandlesHitBlock(Player p, ExtBlock block, EndType ending, Vec3U16 pos, bool doExplode) {
|
||||
if (p.level.physics < 2 || ending == EndType.Teleport || ending == EndType.Normal) return true;
|
||||
protected static bool HandlesHitBlock(Player p, ExtBlock block, WeaponType ending, Vec3U16 pos, bool doExplode) {
|
||||
if (p.level.physics < 2 || ending == WeaponType.Teleport || ending == WeaponType.Normal) return true;
|
||||
|
||||
if (ending == EndType.Destroy) {
|
||||
if (ending == WeaponType.Destroy) {
|
||||
bool fireKills = block.BlockID != Block.air && p.level.BlockProps[block.Index].LavaKills;
|
||||
if ((!fireKills && !Block.NeedRestart(block.BlockID)) && block.BlockID != Block.glass) {
|
||||
return true;
|
||||
@ -180,7 +208,6 @@ namespace MCGalaxy.Commands.Fun {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected struct CatchPos { public EndType ending; }
|
||||
protected enum EndType { Invalid, Normal, Destroy, Teleport, Explode, Laser };
|
||||
protected enum WeaponType { Invalid, Normal, Destroy, Teleport, Explode, Laser };
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user