Add client-side terrain replacement when terrain add is rejected
This commit is contained in:
parent
7c76c27126
commit
476d6382da
14 changed files with 427 additions and 45 deletions
|
@ -14,9 +14,6 @@ namespace CLre.API.App
|
||||||
if (gameEngineReady != null) gameEngineReady(this, new GameReady { });
|
if (gameEngineReady != null) gameEngineReady(this, new GameReady { });
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEntitiesDB entitiesDB { get; set; }
|
|
||||||
public override IEntityFactory entityFactory { get; set; }
|
|
||||||
|
|
||||||
public void OnFrameworkInitialized()
|
public void OnFrameworkInitialized()
|
||||||
{
|
{
|
||||||
// TODO framework init event
|
// TODO framework init event
|
||||||
|
@ -33,9 +30,6 @@ namespace CLre.API.App
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEntitiesDB entitiesDB { get; set; }
|
|
||||||
public override IEntityFactory entityFactory { get; set; }
|
|
||||||
|
|
||||||
public void OnFrameworkInitialized()
|
public void OnFrameworkInitialized()
|
||||||
{
|
{
|
||||||
if (gameFrameworkReady != null) gameFrameworkReady(this, new GameReady { });
|
if (gameFrameworkReady != null) gameFrameworkReady(this, new GameReady { });
|
||||||
|
@ -55,8 +49,5 @@ namespace CLre.API.App
|
||||||
{
|
{
|
||||||
if (menuEngineReady != null) menuEngineReady(this, new MenuReady { });
|
if (menuEngineReady != null) menuEngineReady(this, new MenuReady { });
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEntitiesDB entitiesDB { get; set; }
|
|
||||||
public override IEntityFactory entityFactory { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -54,9 +54,6 @@ namespace CLre.API.Characters
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEntitiesDB entitiesDB { get; set; }
|
|
||||||
public override IEntityFactory entityFactory { get; set; }
|
|
||||||
|
|
||||||
public bool GetGodModeRequested()
|
public bool GetGodModeRequested()
|
||||||
{
|
{
|
||||||
if (entitiesDB == null) return false;
|
if (entitiesDB == null) return false;
|
||||||
|
|
|
@ -21,8 +21,8 @@ namespace CLre.API.Engines
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Ready();
|
public abstract void Ready();
|
||||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
public IEntitiesDB entitiesDB { get; set; }
|
||||||
public abstract IEntityFactory entityFactory { get; set; }
|
public IEntityFactory entityFactory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -41,8 +41,8 @@ namespace CLre.API.Engines
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Ready();
|
public abstract void Ready();
|
||||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
public IEntitiesDB entitiesDB { get; set; }
|
||||||
public abstract IEntityFactory entityFactory { get; set; }
|
public IEntityFactory entityFactory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -60,8 +60,8 @@ namespace CLre.API.Engines
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Ready();
|
public abstract void Ready();
|
||||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
public IEntitiesDB entitiesDB { get; set; }
|
||||||
public abstract IEntityFactory entityFactory { get; set; }
|
public IEntityFactory entityFactory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -79,8 +79,8 @@ namespace CLre.API.Engines
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Ready();
|
public abstract void Ready();
|
||||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
public IEntitiesDB entitiesDB { get; set; }
|
||||||
public abstract IEntityFactory entityFactory { get; set; }
|
public IEntityFactory entityFactory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(FrontEnd.MainFrontEnd), "BuildEngines")]
|
[HarmonyPatch(typeof(FrontEnd.MainFrontEnd), "BuildEngines")]
|
||||||
|
|
|
@ -12,8 +12,8 @@ namespace CLre.API.Engines
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Ready();
|
public abstract void Ready();
|
||||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
public IEntitiesDB entitiesDB { get; set; }
|
||||||
public abstract IEntityFactory entityFactory { get; set; }
|
public IEntityFactory entityFactory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class GameObsoleteEnginePostBuild : ICLreEngine
|
public abstract class GameObsoleteEnginePostBuild : ICLreEngine
|
||||||
|
@ -24,8 +24,8 @@ namespace CLre.API.Engines
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Ready();
|
public abstract void Ready();
|
||||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
public IEntitiesDB entitiesDB { get; set; }
|
||||||
public abstract IEntityFactory entityFactory { get; set; }
|
public IEntityFactory entityFactory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(GameFramework.MainLevel), "BuildDeprecatedEngines")]
|
[HarmonyPatch(typeof(GameFramework.MainLevel), "BuildDeprecatedEngines")]
|
||||||
|
|
|
@ -3,6 +3,7 @@ using CLre.API.Engines;
|
||||||
using GameNetworkLayer.Shared;
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using VoxelFarm.GameServer;
|
||||||
|
|
||||||
namespace CLre.API.Synergy
|
namespace CLre.API.Synergy
|
||||||
{
|
{
|
||||||
|
@ -40,9 +41,6 @@ namespace CLre.API.Synergy
|
||||||
Utility.Logging.MetaLog($"Received CLre handshake! {p}");
|
Utility.Logging.MetaLog($"Received CLre handshake! {p}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEntitiesDB entitiesDB { get; set; }
|
|
||||||
public override IEntityFactory entityFactory { get; set; }
|
|
||||||
|
|
||||||
public IEnumerator Sender(SerializedCLreHandshake payload)
|
public IEnumerator Sender(SerializedCLreHandshake payload)
|
||||||
{
|
{
|
||||||
yield return null;
|
yield return null;
|
||||||
|
@ -73,11 +71,14 @@ namespace CLre.API.Synergy
|
||||||
|
|
||||||
internal static object netMessageSender;
|
internal static object netMessageSender;
|
||||||
|
|
||||||
|
internal static TerrainModelClientServer tmcs;
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
public static void AfterMethodCall(object ____netMessageListener, object ____netMessageSender)
|
public static void AfterMethodCall(object ____netMessageListener, object ____netMessageSender, TerrainModelClientServer ____terrainModelServerPrediction)
|
||||||
{
|
{
|
||||||
netMessageListener = ____netMessageListener;
|
netMessageListener = ____netMessageListener;
|
||||||
netMessageSender = ____netMessageSender;
|
netMessageSender = ____netMessageSender;
|
||||||
|
tmcs = ____terrainModelServerPrediction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -54,9 +54,6 @@ namespace CLre.API.Synergy
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEntitiesDB entitiesDB { get; set; }
|
|
||||||
public override IEntityFactory entityFactory { get; set; }
|
|
||||||
|
|
||||||
public ClientMessagingEngine(): base()
|
public ClientMessagingEngine(): base()
|
||||||
{
|
{
|
||||||
App.Client.GameJoin += (_, __) => { MessageSender().Run(); };
|
App.Client.GameJoin += (_, __) => { MessageSender().Run(); };
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Game.Handhelds;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace CLre.API.Synergy.Tweaks
|
||||||
|
{
|
||||||
|
public struct SerializedCLreTerrainModifyRejection: ISerializedNetData
|
||||||
|
{
|
||||||
|
public RejectionFlag Flags;
|
||||||
|
|
||||||
|
public uint resourceId;
|
||||||
|
|
||||||
|
public Vector3 hit;
|
||||||
|
|
||||||
|
public string toolKey;
|
||||||
|
|
||||||
|
public ToolModeType toolMode;
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
writer.Write((byte)Flags);
|
||||||
|
writer.Write(resourceId);
|
||||||
|
writer.Write(hit.x);
|
||||||
|
writer.Write(hit.y);
|
||||||
|
writer.Write(hit.z);
|
||||||
|
writer.Write(toolKey);
|
||||||
|
writer.Write((byte)toolMode);
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (BinaryReader reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
Flags = (RejectionFlag)reader.ReadByte();
|
||||||
|
resourceId = reader.ReadUInt32();
|
||||||
|
float x = reader.ReadSingle();
|
||||||
|
float y = reader.ReadSingle();
|
||||||
|
float z = reader.ReadSingle();
|
||||||
|
hit = new Vector3(x, y, z);
|
||||||
|
toolKey = reader.ReadString();
|
||||||
|
toolMode = (ToolModeType)reader.ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool Ok()
|
||||||
|
{
|
||||||
|
return (Flags & RejectionFlag.Rejection) == RejectionFlag.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum RejectionFlag : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Rejection = 1,
|
||||||
|
Proximity = 1 << 1,
|
||||||
|
Permission = 1 << 2,
|
||||||
|
AccountNotFound = 1 << 3,
|
||||||
|
InitError = 1 << 4,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Game.DataLoader;
|
||||||
using GameNetworkLayer.Client;
|
using GameNetworkLayer.Client;
|
||||||
using GameNetworkLayer.Shared;
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using NetworkFramework.Shared;
|
using NetworkFramework.Shared;
|
||||||
|
using OpenCVForUnity;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
@ -34,6 +37,10 @@ namespace CLre.API.Utility
|
||||||
|
|
||||||
public delegate void INetMsgClientListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBClient<T> proc) where T: struct, ISerializedNetData;
|
public delegate void INetMsgClientListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBClient<T> proc) where T: struct, ISerializedNetData;
|
||||||
|
|
||||||
|
public delegate void DeprecatedDispatcher_Dispatch<T>(ref T value);
|
||||||
|
|
||||||
|
public delegate Dictionary<string, BaseData> IDataDB_GetValues();
|
||||||
|
|
||||||
// useful reflection functions
|
// useful reflection functions
|
||||||
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace CLre
|
||||||
Fixes.InitLogSooner.Init();
|
Fixes.InitLogSooner.Init();
|
||||||
Fixes.MiniScreenHelper.Init();
|
Fixes.MiniScreenHelper.Init();
|
||||||
Fixes.UnderStructureCollider.Init();
|
Fixes.UnderStructureCollider.Init();
|
||||||
|
Fixes.TerrainModifyReset.Init();
|
||||||
|
|
||||||
// API init
|
// API init
|
||||||
API.Synergy.ClientHandshakeEngine.Init();
|
API.Synergy.ClientHandshakeEngine.Init();
|
||||||
|
@ -106,7 +107,11 @@ namespace CLre
|
||||||
|
|
||||||
API.App.Client.MenuReady += (_, __) => { API.Utility.Logging.MetaLog("Menu engine ready event fired!"); };
|
API.App.Client.MenuReady += (_, __) => { API.Utility.Logging.MetaLog("Menu engine ready event fired!"); };
|
||||||
API.App.Client.GameReady += (_, __) => { API.Utility.Logging.MetaLog("Game engine ready event fired!"); };
|
API.App.Client.GameReady += (_, __) => { API.Utility.Logging.MetaLog("Game engine ready event fired!"); };
|
||||||
API.App.Client.GameFrameworkReady += (_, __) => { API.Utility.Logging.MetaLog("Game framework ready event fired!"); };
|
API.App.Client.GameFrameworkReady += (_, __) =>
|
||||||
|
{
|
||||||
|
API.Utility.Logging.MetaLog("Game framework ready event fired!");
|
||||||
|
API.Utility.Logging.MetaLog($"PhotonChat Connection Protocol: {PhotonChatUI.Chat.Instance.ConnectionProtocol}");
|
||||||
|
};
|
||||||
API.App.Client.GameFrameworkExit += (_, __) => { API.Utility.Logging.MetaLog("Game framework exit event fired!"); };
|
API.App.Client.GameFrameworkExit += (_, __) => { API.Utility.Logging.MetaLog("Game framework exit event fired!"); };
|
||||||
|
|
||||||
Character c = Character.Local();
|
Character c = Character.Local();
|
||||||
|
|
244
CLre/Fixes/TerrainModifyReset.cs
Normal file
244
CLre/Fixes/TerrainModifyReset.cs
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using CLre.API.Synergy;
|
||||||
|
using CLre.API.Utility;
|
||||||
|
using Game.DataLoader;
|
||||||
|
using Game.Handhelds;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using HarmonyLib;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using UnityEngine;
|
||||||
|
using VoxelFarm.GameServer;
|
||||||
|
|
||||||
|
namespace CLre.Fixes
|
||||||
|
{
|
||||||
|
[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.Initialiser, id = 8)]
|
||||||
|
public class TerrainModifyReset
|
||||||
|
{
|
||||||
|
private static TerrainModifyResetEngine _tmrEngine = null;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
_tmrEngine = new TerrainModifyResetEngine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.Workaround, id = 8)]
|
||||||
|
public class TerrainModifyResetEngine : API.Engines.GameObsoleteEnginePostBuild, IDataAccess
|
||||||
|
{
|
||||||
|
private Reflection.INetMsgClientListener_RegisterListener<API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection> _registerListener;
|
||||||
|
|
||||||
|
public override void Ready()
|
||||||
|
{
|
||||||
|
_registerListener =
|
||||||
|
Reflection.MethodAsDelegate<Reflection.INetMsgClientListener_RegisterListener<API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection>>(
|
||||||
|
"GameNetworkLayer.Client.NetMessageClientListener:RegisterListener",
|
||||||
|
generics: new [] {typeof(API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection)},
|
||||||
|
instance: MainLevel_BuildClasses_Patch.netMessageListener);
|
||||||
|
_registerListener(NetworkDispatcherCode.TerrainModificationFailed, OnMessageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMessageReceived(ref API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection data)
|
||||||
|
{
|
||||||
|
if (!data.Ok())
|
||||||
|
{
|
||||||
|
// reset terrain visuals
|
||||||
|
// TODO optimise
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog($"data.resourceId: {data.resourceId}");
|
||||||
|
#endif
|
||||||
|
AddTerrain(ref data);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void GetTerrainRelativePosition(ref Vector3 pos)
|
||||||
|
{
|
||||||
|
// This uses decompiled code from VoxelFarm.Shared.VoxelFarmGameUtils:GetTerrainRelativePosition
|
||||||
|
// there's no point in calling that simple function when I have to jump through hoops with reflection
|
||||||
|
//
|
||||||
|
// there's also nothing particularly unique (ie copyrightable) about this code,
|
||||||
|
// so the lawyers can suck it (also suing a benevolent project is a shitty move)
|
||||||
|
pos.x /= 0.083333336f;
|
||||||
|
pos.y /= 0.041666668f;
|
||||||
|
pos.z /= 0.083333336f;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void AddTerrain(ref API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection data)
|
||||||
|
{
|
||||||
|
// This uses decompiled code from VoxelFarm.GameServer.TerrainModelClientServer:AddTerrain
|
||||||
|
// there's no point in calling that simple function when I have to jump through hoops with reflection
|
||||||
|
// to supply the parameters to it
|
||||||
|
//
|
||||||
|
// Also this is not unique functionality, and comes from the logic of how the placement modes work
|
||||||
|
switch (data.toolMode)
|
||||||
|
{
|
||||||
|
case ToolModeType.Block:
|
||||||
|
MainLevel_BuildClasses_Patch.tmcs.AddDisc(0, data.hit, (int)data.resourceId, 5, 5);
|
||||||
|
break;
|
||||||
|
case ToolModeType.Disc:
|
||||||
|
MainLevel_BuildClasses_Patch.tmcs.AddDisc(0, data.hit, (int)data.resourceId, 1, 5);
|
||||||
|
break;
|
||||||
|
case ToolModeType.Voxel:
|
||||||
|
MainLevel_BuildClasses_Patch.tmcs.AddSingleVoxel(0, data.hit, (int)data.resourceId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDataDB dataDB { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.HarmonyPatch, id = 8)]
|
||||||
|
[HarmonyPatch]
|
||||||
|
class TerrainPendingModificationEngineClient_Add_Patch
|
||||||
|
{
|
||||||
|
internal static object _terrainModifyInputNode = null;
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static void BeforeMethodCall(object node)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog("Intercepting VoxelFarm.Client.TerrainPendingModificationEngineClient:Add()");
|
||||||
|
#endif
|
||||||
|
_terrainModifyInputNode = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("VoxelFarm.Client.TerrainPendingModificationEngineClient:Add", new []{ AccessTools.TypeByName("VoxelFarm.Shared.TerrainModifyInputNode")});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.HarmonyPatch, id = 8)]
|
||||||
|
[HarmonyPatch]
|
||||||
|
class TerrainPendingModificationEngineClient_OnBlockRemoved_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool BeforeMethodCall(int sender, ref ISerializedNetData terrainModifyInputData)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog($"Intercepting VoxelFarm.Client.TerrainPendingModificationEngineClient:OnBlockRemoved({sender}, {terrainModifyInputData})");
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("VoxelFarm.Client.TerrainPendingModificationEngineClient:OnBlockRemoved");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.Debug, id = 8)]
|
||||||
|
[HarmonyPatch]
|
||||||
|
class SpadeEngine_FinishDigging_Patch
|
||||||
|
{
|
||||||
|
internal static int CurrentMaterialId = 0;
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static void BeforeMethodCall(object toolNode, int ____currentMaterialId)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog($"Intercepting Game.Handhelds.SpadeEngine:FinishDigging:GetTerrainMaterial(...) material:{____currentMaterialId}");
|
||||||
|
#endif
|
||||||
|
CurrentMaterialId = ____currentMaterialId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("Game.Handhelds.SpadeEngine:FinishDigging");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.Debug, id = 8)]
|
||||||
|
[HarmonyPatch]
|
||||||
|
class TerrainModifyInputData_InjectValues_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static void BeforeMethodCall(ref uint resourceId)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog($"VoxelFarm.Shared.TerrainModifyInputData:InjectValues({resourceId}, ...)");
|
||||||
|
#endif
|
||||||
|
if (resourceId == 0) resourceId = (uint) SpadeEngine_FinishDigging_Patch.CurrentMaterialId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("VoxelFarm.Shared.TerrainModifyInputData:InjectValues");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.HarmonyPatch, id = 8)]
|
||||||
|
[HarmonyPatch]
|
||||||
|
class NetMessageClientListener_RegisterListener_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool BeforeMethodCall(NetworkDispatcherCode code)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog($"Intercepting GameNetworkLayer.Client.NetMessageClientListener:RegisterListener({code}, ...)");
|
||||||
|
#endif
|
||||||
|
// don't allow for standard TerrainModificationFailed listener to be registered
|
||||||
|
// because it's a different type and that's illegal
|
||||||
|
return code != NetworkDispatcherCode.TerrainModificationFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("GameNetworkLayer.Client.NetMessageClientListener:RegisterListener", generics: new []{ typeof(SerializedEmptyNetData)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this disables terrain destruction
|
||||||
|
/*[Bugfix(name = "TerrainModificationFailedHandler",
|
||||||
|
description = "Actually handle TerrainModificationFailed network messages",
|
||||||
|
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
|
||||||
|
component = BugfixType.Debug, id = 8)]
|
||||||
|
[HarmonyPatch]
|
||||||
|
class TerrainModificationEngineServer_RemoveTerrainInput_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool BeforeMethodCall(int senderPlayerId, ref ISerializedNetData data)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog($"Intercepting client-side GameServer.VoxelFarm.Server.TerrainModificationEngineServer:RemoveTerrainInput({senderPlayerId}, {data})");
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("GameServer.VoxelFarm.Server.TerrainModificationEngineServer:RemoveTerrainInput");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Game.Handhelds;
|
||||||
using NetworkFramework.Shared;
|
using NetworkFramework.Shared;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace CLre_server.API.Synergy.Tweaks
|
namespace CLre_server.API.Synergy.Tweaks
|
||||||
{
|
{
|
||||||
|
@ -9,7 +11,13 @@ namespace CLre_server.API.Synergy.Tweaks
|
||||||
{
|
{
|
||||||
public RejectionFlag Flags;
|
public RejectionFlag Flags;
|
||||||
|
|
||||||
public uint Cell;
|
public uint resourceId;
|
||||||
|
|
||||||
|
public Vector3 hit;
|
||||||
|
|
||||||
|
public string toolKey;
|
||||||
|
|
||||||
|
public ToolModeType toolMode;
|
||||||
|
|
||||||
public byte[] Serialize()
|
public byte[] Serialize()
|
||||||
{
|
{
|
||||||
|
@ -18,7 +26,12 @@ namespace CLre_server.API.Synergy.Tweaks
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
{
|
{
|
||||||
writer.Write((byte)Flags);
|
writer.Write((byte)Flags);
|
||||||
writer.Write(Cell);
|
writer.Write(resourceId);
|
||||||
|
writer.Write(hit.x);
|
||||||
|
writer.Write(hit.y);
|
||||||
|
writer.Write(hit.z);
|
||||||
|
writer.Write(toolKey);
|
||||||
|
writer.Write((byte)toolMode);
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +44,13 @@ namespace CLre_server.API.Synergy.Tweaks
|
||||||
using (BinaryReader reader = new BinaryReader(stream))
|
using (BinaryReader reader = new BinaryReader(stream))
|
||||||
{
|
{
|
||||||
Flags = (RejectionFlag)reader.ReadByte();
|
Flags = (RejectionFlag)reader.ReadByte();
|
||||||
Cell = reader.ReadUInt32();
|
resourceId = reader.ReadUInt32();
|
||||||
|
float x = reader.ReadSingle();
|
||||||
|
float y = reader.ReadSingle();
|
||||||
|
float z = reader.ReadSingle();
|
||||||
|
hit = new Vector3(x, y, z);
|
||||||
|
toolKey = reader.ReadString();
|
||||||
|
toolMode = (ToolModeType)reader.ReadByte();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,5 +51,21 @@ namespace CLre_server.API.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AccessTools), "Method",
|
||||||
|
new Type[] {typeof(Type), typeof(string), typeof(Type[]), typeof(Type[])})]
|
||||||
|
class AccessTools_Method2_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(MethodInfo __result, Type type, string name)
|
||||||
|
{
|
||||||
|
if (!AccessToolsWarnings.isEnabled) return;
|
||||||
|
if (__result == null)
|
||||||
|
{
|
||||||
|
var method = (new StackTrace()).GetFrame(2).GetMethod();
|
||||||
|
Utility.Logging.LogWarning($"[{method.DeclaringType.FullName}.{method.Name}] AccessTools.Method(\"{type}\", \"{name}\") returned null result");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Game.DataLoader;
|
||||||
using GameNetworkLayer.Shared;
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using NetworkFramework.Shared;
|
using NetworkFramework.Shared;
|
||||||
|
@ -33,6 +35,7 @@ namespace CLre_server.API.Utility
|
||||||
|
|
||||||
public delegate void INetMsgServerListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBServer<T> proc) where T: struct, ISerializedNetData;
|
public delegate void INetMsgServerListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBServer<T> proc) where T: struct, ISerializedNetData;
|
||||||
|
|
||||||
|
public delegate Dictionary<string, BaseData> IDataDB_GetValues();
|
||||||
|
|
||||||
// useful reflection functions
|
// useful reflection functions
|
||||||
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using CLre_server.API.Synergy.Tweaks;
|
using CLre_server.API.Synergy.Tweaks;
|
||||||
|
using CLre_server.API.Utility;
|
||||||
using Game.DataLoader;
|
using Game.DataLoader;
|
||||||
using GameNetworkLayer.Shared;
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
@ -12,6 +13,7 @@ using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using User.Server;
|
using User.Server;
|
||||||
|
using voxelfarm;
|
||||||
|
|
||||||
namespace CLre_server.Tweaks
|
namespace CLre_server.Tweaks
|
||||||
{
|
{
|
||||||
|
@ -104,8 +106,6 @@ namespace CLre_server.Tweaks
|
||||||
#endif
|
#endif
|
||||||
if (isPointInAABB)
|
if (isPointInAABB)
|
||||||
{
|
{
|
||||||
result.Cell = item;
|
|
||||||
|
|
||||||
if (!isOwner)
|
if (!isOwner)
|
||||||
{
|
{
|
||||||
result.Flags = RejectionFlag.Proximity
|
result.Flags = RejectionFlag.Proximity
|
||||||
|
@ -154,19 +154,24 @@ namespace CLre_server.Tweaks
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
class TerrainModificationEngineServer_RemoveTerrainInput_Patch
|
class TerrainModificationEngineServer_RemoveTerrainInput_Patch
|
||||||
{
|
{
|
||||||
|
private static object _netMsgServerSender;
|
||||||
|
|
||||||
|
// reflection caching
|
||||||
private static API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
|
private static API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
|
||||||
_netMessageSend = null;
|
_netMessageSend_CLre = null;
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
public static bool BeforeMethodCall(int senderPlayerId, ref ISerializedNetData data, object ____netMsgServerSender)
|
public static bool BeforeMethodCall(int senderPlayerId, ref ISerializedNetData data, object ____netMsgServerSender)
|
||||||
{
|
{
|
||||||
if (!CLre.Config.terrain_exclusion_zone) return true;
|
if (!CLre.Config.terrain_exclusion_zone) return true;
|
||||||
if (_netMessageSend == null)
|
_netMsgServerSender = ____netMsgServerSender;
|
||||||
|
if (_netMessageSend_CLre == null)
|
||||||
{
|
{
|
||||||
|
// cache reflection operations on first run
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
API.Utility.Logging.MetaLog("Building SendMessage delegate optimisation");
|
API.Utility.Logging.MetaLog("Building SendMessage delegate optimisation");
|
||||||
#endif
|
#endif
|
||||||
_netMessageSend = API.Utility.Reflection
|
_netMessageSend_CLre = API.Utility.Reflection
|
||||||
.MethodAsDelegate<
|
.MethodAsDelegate<
|
||||||
API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
|
API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
|
||||||
>(
|
>(
|
||||||
|
@ -185,8 +190,30 @@ namespace CLre_server.Tweaks
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
API.Utility.Logging.MetaLog("Rejecting terrain modification");
|
API.Utility.Logging.MetaLog("Rejecting terrain modification");
|
||||||
#endif
|
#endif
|
||||||
|
// TODO optimize
|
||||||
|
Traverse tmid = Traverse.Create(data);
|
||||||
|
modifyPayload.resourceId = tmid.Property<uint>("resourceId").Value;
|
||||||
|
modifyPayload.hit = location;
|
||||||
|
//modifyPayload.materialIndex = tmid.Property<int>("materialIndex").Value;
|
||||||
|
modifyPayload.toolKey = tmid.Property<string>("toolKey").Value;
|
||||||
|
modifyPayload.toolMode = tmid.Property<Game.Handhelds.ToolModeType>("toolMode").Value;
|
||||||
|
switch (modifyPayload.toolMode)
|
||||||
|
{
|
||||||
|
case Game.Handhelds.ToolModeType.Block:
|
||||||
|
modifyPayload.hit.y -= 0.125f * 2; // each layer is 0.125 thick, block is 3 layers
|
||||||
|
break;
|
||||||
|
case Game.Handhelds.ToolModeType.Disc:
|
||||||
|
break;
|
||||||
|
case Game.Handhelds.ToolModeType.Voxel:
|
||||||
|
modifyPayload.toolMode = Game.Handhelds.ToolModeType.Disc; // voxels aren't replaced properly
|
||||||
|
break;
|
||||||
|
}
|
||||||
// signal client that stuff failed
|
// signal client that stuff failed
|
||||||
_netMessageSend(NetworkDispatcherCode.TerrainModificationFailed, ref modifyPayload, senderPlayerId);
|
_netMessageSend_CLre(NetworkDispatcherCode.TerrainModificationFailed, ref modifyPayload, senderPlayerId);
|
||||||
|
// build terrain data for terrain replacement
|
||||||
|
#if DEBUG
|
||||||
|
API.Utility.Logging.MetaLog("Filling hole left by terrain modification");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return modifyPayload.Ok();
|
return modifyPayload.Ok();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue