added status effect saving

- added some of the packets to add/remove effects (todo: battle packet too)
This commit is contained in:
Tahir Akhlaq 2017-07-16 17:35:10 +01:00
parent d9d185d7e6
commit 53207a9ff0
7 changed files with 132 additions and 56 deletions

View File

@ -1799,6 +1799,36 @@ namespace FFXIVClassic_Map_Server
} }
return effects; return effects;
} }
public static void SavePlayerStatusEffects(Player player)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
// we'll run them all at once instead of one at a time
string queries = "";
foreach (var effect in player.statusEffects.GetStatusEffects())
{
var duration = effect.GetDurationMs() + effect.GetStartTime().Millisecond - Program.Tick.Millisecond;
queries += Environment.NewLine + $"REPLACE INTO characters_statuseffect(characterId, statusId, magnitude, duration, tick, tier, extra) VALUES ({player.actorId}, {effect.GetEffectId()}, {effect.GetMagnitude()}, {duration}, {effect.GetTickMs()}, {effect.GetTier()}, {effect.GetExtra()});";
}
MySqlCommand cmd = new MySqlCommand(queries, conn);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
} }
} }

View File

@ -1,5 +1,6 @@
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -440,6 +441,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
return (uint)id; return (uint)id;
} }
public ushort GetEffectIdForCharaWork()
{
return (ushort)(id - 200000);
}
public DateTime GetStartTime()
{
return startTime;
}
public string GetName() public string GetName()
{ {
return name; return name;
@ -480,6 +491,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
return (byte)overwrite; return (byte)overwrite;
} }
public void SetStartTime(DateTime time)
{
this.startTime = time;
this.lastTick = time;
}
public void SetOwner(Character owner) public void SetOwner(Character owner)
{ {
this.owner = owner; this.owner = owner;

View File

@ -16,11 +16,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{ {
private Character owner; private Character owner;
private readonly Dictionary<uint, StatusEffect> effects; private readonly Dictionary<uint, StatusEffect> effects;
public static readonly int MAX_EFFECTS = 20;
public StatusEffectContainer(Character owner) public StatusEffectContainer(Character owner)
{ {
this.owner = owner; this.owner = owner;
this.effects = new Dictionary<uint, StatusEffect>(20); this.effects = new Dictionary<uint, StatusEffect>();
} }
public void Update(DateTime tick) public void Update(DateTime tick)
@ -54,9 +55,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
(overwritable == (uint)StatusEffectOverwrite.GreaterOrEqualTo && (effect.GetDurationMs() == newEffect.GetDurationMs() || effect.GetMagnitude() == newEffect.GetMagnitude())); (overwritable == (uint)StatusEffectOverwrite.GreaterOrEqualTo && (effect.GetDurationMs() == newEffect.GetDurationMs() || effect.GetMagnitude() == newEffect.GetMagnitude()));
} }
if (canOverwrite || effects.ContainsKey(effect.GetEffectId())) if (canOverwrite || effect == null)
{ {
if (!silent || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0) if (!silent || (effect?.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
{ {
// todo: send packet to client with effect added message // todo: send packet to client with effect added message
} }
@ -65,9 +66,18 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
effects.Remove(effect.GetEffectId()); effects.Remove(effect.GetEffectId());
effects.Add(newEffect.GetEffectId(), newEffect); effects.Add(newEffect.GetEffectId(), newEffect);
// todo: this is retarded..
{
var index = Array.IndexOf(effects.Values.ToArray(), newEffect);
owner.charaWork.status[index] = effect.GetEffectIdForCharaWork();
owner.charaWork.statusShownTime[index] = effect.GetDurationMs() / 1000;
this.owner.zone.BroadcastPacketAroundActor(this.owner, SetActorStatusPacket.BuildPacket(this.owner.actorId, (ushort)index, (ushort)effect.GetEffectId()));
} }
return true; return true;
} }
return false;
}
public void RemoveStatusEffect(StatusEffect effect, bool silent = false) public void RemoveStatusEffect(StatusEffect effect, bool silent = false)
{ {
@ -76,10 +86,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// send packet to client with effect remove message // send packet to client with effect remove message
if (!silent || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0) if (!silent || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
{ {
// todo: send packet to client with effect added message // todo: send packet to client with effect removed message
} }
// function onLose(actor, effec) // todo: this is retarded..
{
var index = Array.IndexOf(effects.Values.ToArray(), effect);
owner.charaWork.status[index] = effect.GetEffectIdForCharaWork();
this.owner.zone.BroadcastPacketAroundActor(this.owner, SetActorStatusPacket.BuildPacket(owner.actorId, (ushort)index, (ushort)0));
}
// function onLose(actor, effect
LuaEngine.CallLuaStatusEffectFunction(this.owner, effect, "onLose", this.owner, effect); LuaEngine.CallLuaStatusEffectFunction(this.owner, effect, "onLose", this.owner, effect);
effects.Remove(effect.GetEffectId()); effects.Remove(effect.GetEffectId());
} }
@ -158,5 +174,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{ {
return effects.Values; return effects.Values;
} }
void SaveStatusEffectsToDatabase(StatusEffectFlags removeEffectFlags = StatusEffectFlags.None)
{
if (owner is Player)
{
Database.SavePlayerStatusEffects((Player)owner);
}
}
} }
} }

View File

@ -50,7 +50,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{ {
var damage = utils.AttackUtils.CalculateDamage(owner, target); var damage = utils.AttackUtils.CalculateDamage(owner, target);
lua.LuaEngine.GetInstance().CallLuaFunction(owner, target, "onAttack", false, damage); // onAttack(actor, target, damage)
lua.LuaEngine.CallLuaBattleAction(owner, "onAttack", false, owner, target, damage);
//var packet = BattleAction1Packet.BuildPacket(owner.actorId, target.actorId); //var packet = BattleAction1Packet.BuildPacket(owner.actorId, target.actorId);

View File

@ -684,6 +684,7 @@ namespace FFXIVClassic_Map_Server.Actors
//Save Player //Save Player
Database.SavePlayerPlayTime(this); Database.SavePlayerPlayTime(this);
Database.SavePlayerPosition(this); Database.SavePlayerPosition(this);
Database.SavePlayerStatusEffects(this);
} }
public void CleanupAndSave(uint destinationZone, ushort spawnType, float destinationX, float destinationY, float destinationZ, float destinationRot) public void CleanupAndSave(uint destinationZone, ushort spawnType, float destinationX, float destinationY, float destinationZ, float destinationRot)
@ -707,6 +708,8 @@ namespace FFXIVClassic_Map_Server.Actors
//Save Player //Save Player
Database.SavePlayerPlayTime(this); Database.SavePlayerPlayTime(this);
Database.SavePlayerPosition(this); Database.SavePlayerPosition(this);
this.statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnZoning, true);
Database.SavePlayerStatusEffects(this);
} }
public Area GetZone() public Area GetZone()
@ -721,13 +724,16 @@ namespace FFXIVClassic_Map_Server.Actors
public void Logout() public void Logout()
{ {
// todo: really this should be in CleanupAndSave but we might want logout/disconnect handled separately for some effects
QueuePacket(LogoutPacket.BuildPacket(actorId)); QueuePacket(LogoutPacket.BuildPacket(actorId));
statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnLogout);
CleanupAndSave(); CleanupAndSave();
} }
public void QuitGame() public void QuitGame()
{ {
QueuePacket(QuitPacket.BuildPacket(actorId)); QueuePacket(QuitPacket.BuildPacket(actorId));
statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnLogout);
CleanupAndSave(); CleanupAndSave();
} }

View File

@ -134,14 +134,16 @@ namespace FFXIVClassic_Map_Server.lua
/// // todo: this is dumb, should probably make a function for each action with different default return values /// // todo: this is dumb, should probably make a function for each action with different default return values
/// or just make generic function and pass default value as first arg after functionName /// or just make generic function and pass default value as first arg after functionName
/// </summary> /// </summary>
public static void CallLuaMonsterAction(Character actor, string functionName, params object[] args) public static void CallLuaBattleAction(Character actor, string functionName, params object[] args)
{ {
// todo: should we call this for players too?
if (actor is BattleNpc)
{
// todo: check this is correct
string path = $"./scripts/unique/{actor.zone.zoneName}/Monster/{actor.customDisplayName}.lua"; string path = $"./scripts/unique/{actor.zone.zoneName}/Monster/{actor.customDisplayName}.lua";
// todo: should we call this for players too?
if (actor is Player)
{
// todo: check this is correct
path = FILEPATH_PLAYER;
}
// dont wanna throw an error if file doesnt exist // dont wanna throw an error if file doesnt exist
if (File.Exists(path)) if (File.Exists(path))
{ {
@ -152,7 +154,7 @@ namespace FFXIVClassic_Map_Server.lua
} }
catch (Exception e) catch (Exception e)
{ {
Program.Log.Error($"LuaEngine.CallLuaMonsterAction [{functionName}] {e.Message}"); Program.Log.Error($"LuaEngine.CallLuaBattleAction [{functionName}] {e.Message}");
} }
DynValue res = new DynValue(); DynValue res = new DynValue();
@ -162,7 +164,6 @@ namespace FFXIVClassic_Map_Server.lua
} }
} }
} }
}
public static int CallLuaStatusEffectFunction(Character actor, StatusEffect effect, string functionName, params object[] args) public static int CallLuaStatusEffectFunction(Character actor, StatusEffect effect, string functionName, params object[] args)
{ {
@ -390,41 +391,40 @@ namespace FFXIVClassic_Map_Server.lua
return null; return null;
} }
public void CallLuaFunction(Actor actor, Actor target, string funcName, bool optional, params object[] args) public void CallLuaFunction(Player player, Actor target, string funcName, bool optional, params object[] args)
{ {
bool isPlayer = actor is Player;
//Need a seperate case for NPCs cause that child/parent thing. //Need a seperate case for NPCs cause that child/parent thing.
if (target is Npc && isPlayer) if (target is Npc)
{ {
CallLuaFunctionNpc((Player)actor, (Npc)target, funcName, optional, args); CallLuaFunctionNpc(player, (Npc)target, funcName, optional, args);
return; return;
} }
object[] args2 = new object[args.Length + 2]; object[] args2 = new object[args.Length + 2];
Array.Copy(args, 0, args2, 2, args.Length); Array.Copy(args, 0, args2, 2, args.Length);
args2[0] = actor; args2[0] = player;
args2[1] = target; args2[1] = target;
string luaPath = GetScriptPath(target); string luaPath = GetScriptPath(target);
LuaScript script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script != null) if (script != null)
{ {
if (!script.Globals.Get(funcName).IsNil() && isPlayer) if (!script.Globals.Get(funcName).IsNil())
{ {
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine; Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
DynValue value = coroutine.Resume(args2); DynValue value = coroutine.Resume(args2);
ResolveResume((Player)actor, coroutine, value); ResolveResume(player, coroutine, value);
} }
else else
{ {
if (!optional) if (!optional)
SendError((Player)actor, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName())); SendError(player, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
} }
} }
else else
{ {
if (!(target is Area) && !optional && isPlayer) if (!(target is Area) && !optional)
SendError((Player)actor, String.Format("Could not find script for actor {0}.", target.GetName())); SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
} }
} }
@ -456,18 +456,16 @@ namespace FFXIVClassic_Map_Server.lua
} }
} }
public DynValue ResolveResume(Actor actor, Coroutine coroutine, DynValue value) public DynValue ResolveResume(Player player, Coroutine coroutine, DynValue value)
{ {
var isPlayer = actor is Player;
if (value == null || value.IsVoid()) if (value == null || value.IsVoid())
return value; return value;
if (isPlayer && value.String != null && value.String.Equals("_WAIT_EVENT")) if (player != null && value.String != null && value.String.Equals("_WAIT_EVENT"))
{ {
GetInstance().AddWaitEventCoroutine((Player)actor, coroutine); GetInstance().AddWaitEventCoroutine(player, coroutine);
} }
else if (isPlayer && value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null) else if (player != null && value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null)
{ {
switch (value.Tuple[0].String) switch (value.Tuple[0].String)
{ {
@ -619,12 +617,12 @@ namespace FFXIVClassic_Map_Server.lua
LuaParam.Insert(1, i - (playerNull ? 2 : 0)); LuaParam.Insert(1, i - (playerNull ? 2 : 0));
// run the script // run the script
script.Call(script.Globals["onTrigger"], LuaParam.ToArray()); //script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
// gm commands dont need to be coroutines? // gm commands dont need to be coroutines?
//Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine; Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine;
//DynValue value = coroutine.Resume(LuaParam.ToArray()); DynValue value = coroutine.Resume(LuaParam.ToArray());
//ResolveResume(player, coroutine, value); LuaEngine.GetInstance().ResolveResume(player, coroutine, value);
return; return;
} }
} }

View File

@ -16,13 +16,13 @@
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- --
-- Table structure for table `status_effect` -- Table structure for table `status_effects`
-- --
DROP TABLE IF EXISTS `status_effect`; DROP TABLE IF EXISTS `status_effects`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `status_effect` ( CREATE TABLE `status_effects` (
`id` smallint(5) unsigned NOT NULL, `id` smallint(5) unsigned NOT NULL,
`name` varchar(128) NOT NULL, `name` varchar(128) NOT NULL,
`flags` int(10) unsigned NOT NULL, `flags` int(10) unsigned NOT NULL,
@ -32,12 +32,12 @@ CREATE TABLE `status_effect` (
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
-- Dumping data for table `status_effect` -- Dumping data for table `status_effects`
-- --
LOCK TABLES `status_effect` WRITE; LOCK TABLES `status_effects` WRITE;
/*!40000 ALTER TABLE `status_effect` DISABLE KEYS */; /*!40000 ALTER TABLE `status_effects` DISABLE KEYS */;
/*!40000 ALTER TABLE `status_effect` ENABLE KEYS */; /*!40000 ALTER TABLE `status_effects` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;