1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-23 21:27:46 +00:00

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

View file

@ -16,11 +16,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{
private Character owner;
private readonly Dictionary<uint, StatusEffect> effects;
public static readonly int MAX_EFFECTS = 20;
public StatusEffectContainer(Character owner)
{
this.owner = owner;
this.effects = new Dictionary<uint, StatusEffect>(20);
this.effects = new Dictionary<uint, StatusEffect>();
}
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()));
}
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
}
@ -65,8 +66,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
effects.Remove(effect.GetEffectId());
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)
@ -76,10 +86,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// send packet to client with effect remove message
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);
effects.Remove(effect.GetEffectId());
}
@ -158,5 +174,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{
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);
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);

View file

@ -684,6 +684,7 @@ namespace FFXIVClassic_Map_Server.Actors
//Save Player
Database.SavePlayerPlayTime(this);
Database.SavePlayerPosition(this);
Database.SavePlayerStatusEffects(this);
}
public void CleanupAndSave(uint destinationZone, ushort spawnType, float destinationX, float destinationY, float destinationZ, float destinationRot)
@ -706,7 +707,9 @@ namespace FFXIVClassic_Map_Server.Actors
//Save Player
Database.SavePlayerPlayTime(this);
Database.SavePlayerPosition(this);
Database.SavePlayerPosition(this);
this.statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnZoning, true);
Database.SavePlayerStatusEffects(this);
}
public Area GetZone()
@ -721,13 +724,16 @@ namespace FFXIVClassic_Map_Server.Actors
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));
statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnLogout);
CleanupAndSave();
}
public void QuitGame()
{
QueuePacket(QuitPacket.BuildPacket(actorId));
statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnLogout);
CleanupAndSave();
}

View file

@ -134,32 +134,33 @@ namespace FFXIVClassic_Map_Server.lua
/// // 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
/// </summary>
public static void CallLuaMonsterAction(Character actor, string functionName, params object[] args)
public static void CallLuaBattleAction(Character actor, string functionName, params object[] args)
{
string path = $"./scripts/unique/{actor.zone.zoneName}/Monster/{actor.customDisplayName}.lua";
// todo: should we call this for players too?
if (actor is BattleNpc)
if (actor is Player)
{
// todo: check this is correct
string path = $"./scripts/unique/{actor.zone.zoneName}/Monster/{actor.customDisplayName}.lua";
// dont wanna throw an error if file doesnt exist
if (File.Exists(path))
path = FILEPATH_PLAYER;
}
// dont wanna throw an error if file doesnt exist
if (File.Exists(path))
{
var script = LoadGlobals();
try
{
var script = LoadGlobals();
try
{
script.DoFile(path);
}
catch (Exception e)
{
Program.Log.Error($"LuaEngine.CallLuaMonsterAction [{functionName}] {e.Message}");
}
DynValue res = new DynValue();
script.DoFile(path);
}
catch (Exception e)
{
Program.Log.Error($"LuaEngine.CallLuaBattleAction [{functionName}] {e.Message}");
}
DynValue res = new DynValue();
if (!script.Globals.Get(functionName).IsNil())
{
res = script.Call(script.Globals.Get(functionName), args);
}
if (!script.Globals.Get(functionName).IsNil())
{
res = script.Call(script.Globals.Get(functionName), args);
}
}
}
@ -390,42 +391,41 @@ namespace FFXIVClassic_Map_Server.lua
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.
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;
}
object[] args2 = new object[args.Length + 2];
Array.Copy(args, 0, args2, 2, args.Length);
args2[0] = actor;
args2[0] = player;
args2[1] = target;
string luaPath = GetScriptPath(target);
LuaScript script = LoadScript(luaPath);
if (script != null)
{
if (!script.Globals.Get(funcName).IsNil() && isPlayer)
if (!script.Globals.Get(funcName).IsNil())
{
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
DynValue value = coroutine.Resume(args2);
ResolveResume((Player)actor, coroutine, value);
ResolveResume(player, coroutine, value);
}
else
{
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
{
if (!(target is Area) && !optional && isPlayer)
SendError((Player)actor, String.Format("Could not find script for actor {0}.", target.GetName()));
}
if (!(target is Area) && !optional)
SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
}
}
public void EventStarted(Player player, Actor target, EventStartPacket eventStart)
@ -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())
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)
{
@ -619,12 +617,12 @@ namespace FFXIVClassic_Map_Server.lua
LuaParam.Insert(1, i - (playerNull ? 2 : 0));
// run the script
script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
//script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
// gm commands dont need to be coroutines?
//Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine;
//DynValue value = coroutine.Resume(LuaParam.ToArray());
//ResolveResume(player, coroutine, value);
Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine;
DynValue value = coroutine.Resume(LuaParam.ToArray());
LuaEngine.GetInstance().ResolveResume(player, coroutine, value);
return;
}
}

View file

@ -16,13 +16,13 @@
/*!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 character_set_client = utf8 */;
CREATE TABLE `status_effect` (
CREATE TABLE `status_effects` (
`id` smallint(5) unsigned NOT NULL,
`name` varchar(128) NOT NULL,
`flags` int(10) unsigned NOT NULL,
@ -32,12 +32,12 @@ CREATE TABLE `status_effect` (
/*!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;
/*!40000 ALTER TABLE `status_effect` DISABLE KEYS */;
/*!40000 ALTER TABLE `status_effect` ENABLE KEYS */;
LOCK TABLES `status_effects` WRITE;
/*!40000 ALTER TABLE `status_effects` DISABLE KEYS */;
/*!40000 ALTER TABLE `status_effects` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;